func (c *Clang) GetDefinition(a *content.GetDefinitionArgs, ret *content.SourceLocation) error { fn, args, err := c.prepare(&a.CompleteAtArgs) if err != nil { return err } args = append([]string{"-fsyntax-only", "-Xclang", "-ast-dump", "-Xclang", "-ast-dump-filter", "-Xclang", a.Identifier}, args...) args = append(args, fn) out, oute, err := RunClang(a.Location.File.Contents, args...) if len(out) == 0 { if err != nil { return err } else { return fmt.Errorf("%s", oute) } } re, err := regexp.Compile(`\w+Decl[^<]+<(..[^:,]+):?(\d+)?:?(\d+)?.*?\s` + a.Identifier + `\s`) if err != nil { return err } res := re.FindAllStringSubmatch(string(out), -1) if len(res) == 0 { return fmt.Errorf("Not found") } ret.File.Name = res[0][1] i, _ := strconv.ParseInt(res[0][2], 10, 32) ret.Line = uint(i) i, _ = strconv.ParseInt(res[0][3], 10, 32) ret.Column = uint(i) return nil }
// Returns the RegionSet visible from the given source code location. // Note that it only uses '{' and '}' to deduce scopes, and further // processing is likely needed depending on language specifics. func Visibility(loc content.SourceLocation) (ret text.RegionSet) { var s SCOPES s.Parse(loc.File.Contents) var rec func(node *parser.Node) pos := int(loc.Offset()) rec = func(node *parser.Node) { for _, child := range node.Children { if !child.Range.Contains(pos) || child.Name == "TextScope" || child.Name == "CommentScope" { r := child.Range if child.Name == "BracketScope" || child.Name == "TextScope" { // We want the brackets (or "'s) as part of the result to make the resulting // source code parseable. r.A += 1 r.B -= 1 } ret = ret.Cut(r) } else { rec(child) } } } root := s.RootNode() ret.Add(root.Range) rec(root) return }
func TestVisibility(t *testing.T) { if d, err := ioutil.ReadFile("../../net/testdata/CompleteSharp.cs"); err != nil { t.Error(err) } else { var p SCOPES if !p.Parse(string(d)) { t.Fatalf("Failed to parse: %s\n%v", p.Error(), p.RootNode()) } tests := []struct { line uint res []text.Region }{ {32, []text.Region{{872, 1090}, {1096, 1158}, {34796, 34846}, {35017, 35067}, {37046, 37049}}}, {116, []text.Region{{872, 1090}, {1096, 1248}, {1337, 1414}, {2803, 2897}, {3812, 3990}, {3991, 4012}, {4108, 4321}, {4533, 4565}, {4565, 4639}, {4988, 5114}, {6210, 6293}, {6672, 6740}, {6927, 7035}, {8232, 8286}, {8500, 8568}, {10533, 10641}, {11209, 11307}, {12510, 12570}, {12645, 12709}, {13010, 13091}, {32050, 32228}, {32343, 32392}, {33297, 33371}, {33636, 33718}, {34790, 34846}, {35017, 35067}, {37046, 37049}}}, {730, []text.Region{{872, 1090}, {1096, 1208}, {32060, 32228}, {32343, 32483}, {32499, 32597}, {32608, 32705}, {32735, 32880}, {33287, 33371}, {33636, 33718}, {34790, 34846}, {35017, 35067}, {37046, 37049}}}, } loc := content.SourceLocation{File: content.File{Contents: string(d)}, Column: 1} for i := range tests { loc.Line = tests[i].line vis := Visibility(loc) if !reflect.DeepEqual(vis.Regions(), tests[i].res) { t.Errorf("Output differs.\nExpected\n%v, got\n%v", tests[i].res, vis.Regions()) } if testing.Verbose() { t.Log(Substr(loc.File.Contents, vis)) } } } }
func TestClang(t *testing.T) { if _, err := RunClang("-v"); err != nil { t.Skipf("Couldn't launch clang: %s", err) } loc := content.SourceLocation{} loc.Column = 1 loc.Line = 10 loc.File.Name = "testdata/hello.cpp" t.Log(CompleteAt([]string{}, loc)) }