diff --git a/dsymbol b/dsymbol index 5b7f06f..5825b71 160000 --- a/dsymbol +++ b/dsymbol @@ -1 +1 @@ -Subproject commit 5b7f06ff005c63a2bf22db0736097ef35b9d36e7 +Subproject commit 5825b717be321f8e69058848322752f5b9d8e698 diff --git a/dub.json b/dub.json index 736ed15..d44925d 100644 --- a/dub.json +++ b/dub.json @@ -7,7 +7,7 @@ ], "license": "GPL-3.0", "dependencies": { - "dsymbol": "~>0.6.4", + "dsymbol": "~>0.7.0", "libdparse": "~>0.11.4", "msgpack-d": "~>1.0.0-beta.7", "stdx-allocator": "~>2.77.5", diff --git a/src/dcd/server/autocomplete/complete.d b/src/dcd/server/autocomplete/complete.d index 1992ded..e374866 100644 --- a/src/dcd/server/autocomplete/complete.d +++ b/src/dcd/server/autocomplete/complete.d @@ -503,7 +503,7 @@ void setCompletions(T)(ref AutocompleteResponse response, CompletionType completionType, bool isBracket = false, string partial = null) { static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r, string p, - size_t[] circularGuard = []) + Scope* completionScope, size_t[] circularGuard = []) { if (circularGuard.canFind(cast(size_t) s)) return; @@ -512,12 +512,13 @@ void setCompletions(T)(ref AutocompleteResponse response, if (sym.name !is null && sym.name.length > 0 && isPublicCompletionKind(sym.kind) && (p is null ? true : toUpper(sym.name.data).startsWith(toUpper(p))) && !r.completions.canFind!(a => a.identifier == sym.name) - && sym.name[0] != '*') + && sym.name[0] != '*' + && mightBeRelevantInCompletionScope(sym, completionScope)) { r.completions ~= makeSymbolCompletionInfo(sym, sym.kind); } if (sym.kind == CompletionKind.importSymbol && !sym.skipOver && sym.type !is null) - addSymToResponse(sym.type, r, p, circularGuard ~ (cast(size_t) s)); + addSymToResponse(sym.type, r, p, completionScope, circularGuard ~ (cast(size_t) s)); } } @@ -527,7 +528,8 @@ void setCompletions(T)(ref AutocompleteResponse response, { auto currentSymbols = completionScope.getSymbolsInCursorScope(cursorPosition); foreach (s; currentSymbols.filter!(a => isPublicCompletionKind(a.kind) - && toUpper(a.name.data).startsWith(toUpper(partial)))) + && toUpper(a.name.data).startsWith(toUpper(partial)) + && mightBeRelevantInCompletionScope(a, completionScope))) { response.completions ~= makeSymbolCompletionInfo(s, s.kind); } @@ -545,7 +547,8 @@ void setCompletions(T)(ref AutocompleteResponse response, && a.kind != CompletionKind.dummy && a.symbolFile == "stdin" && (partial !is null && toUpper(a.name.data).startsWith(toUpper(partial)) - || partial is null))) + || partial is null) + && mightBeRelevantInCompletionScope(a, completionScope))) { response.completions ~= makeSymbolCompletionInfo(s, s.kind); } @@ -574,7 +577,7 @@ void setCompletions(T)(ref AutocompleteResponse response, if (symbols.length == 0) return; } - addSymToResponse(symbols[0], response, partial); + addSymToResponse(symbols[0], response, partial, completionScope); response.completionType = CompletionType.identifiers; } else if (completionType == CompletionType.calltips) @@ -651,6 +654,21 @@ void setCompletions(T)(ref AutocompleteResponse response, } } +bool mightBeRelevantInCompletionScope(const DSymbol* symbol, Scope* scope_) +{ + import dparse.lexer : tok; + + if (symbol.protection == tok!"private" && + !scope_.hasSymbolRecursive(symbol)) + { + // scope is the scope of the current file so if the symbol is not in there, it's not accessible + return false; + } + + return true; +} + + AutocompleteResponse.Completion generateStructConstructorCalltip(const DSymbol* symbol) in { diff --git a/tests/tc_access_modifiers/bar.d b/tests/tc_access_modifiers/bar.d new file mode 100644 index 0000000..ef39b72 --- /dev/null +++ b/tests/tc_access_modifiers/bar.d @@ -0,0 +1,14 @@ +module tc_access_modifiers.bar; + +class Helper +{ + private int mfieldPrivate; + protected int mfieldProtected; + package int mfieldPackage; + int mfieldPublic; + + private void mfuncPrivate() {} + public void mfuncPublic() {} + private static void mfuncPrivateStatic() {} + public static void mfuncPublicStatic() {} +} diff --git a/tests/tc_access_modifiers/expected0.txt b/tests/tc_access_modifiers/expected0.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/tc_access_modifiers/expected1.txt b/tests/tc_access_modifiers/expected1.txt new file mode 100644 index 0000000..a6ac773 --- /dev/null +++ b/tests/tc_access_modifiers/expected1.txt @@ -0,0 +1,4 @@ +identifiers +mfieldPackage v +mfieldProtected v +mfieldPublic v diff --git a/tests/tc_access_modifiers/expected1_1.txt b/tests/tc_access_modifiers/expected1_1.txt new file mode 100644 index 0000000..31f67c3 --- /dev/null +++ b/tests/tc_access_modifiers/expected1_1.txt @@ -0,0 +1,3 @@ +identifiers +mfuncPublic f +mfuncPublicStatic f diff --git a/tests/tc_access_modifiers/expected2.txt b/tests/tc_access_modifiers/expected2.txt new file mode 100644 index 0000000..5769a1d --- /dev/null +++ b/tests/tc_access_modifiers/expected2.txt @@ -0,0 +1,3 @@ +identifiers +myprivate v +mypublic v diff --git a/tests/tc_access_modifiers/expected3.txt b/tests/tc_access_modifiers/expected3.txt new file mode 100644 index 0000000..a6ac773 --- /dev/null +++ b/tests/tc_access_modifiers/expected3.txt @@ -0,0 +1,4 @@ +identifiers +mfieldPackage v +mfieldProtected v +mfieldPublic v diff --git a/tests/tc_access_modifiers/file1.d b/tests/tc_access_modifiers/file1.d new file mode 100644 index 0000000..4ef99cd --- /dev/null +++ b/tests/tc_access_modifiers/file1.d @@ -0,0 +1,16 @@ +import tc_access_modifiers.bar; + +struct X +{ + public int mypublic; + private int myprivate; +} + +void main() +{ + Helper helper; + helper.mfield; + helper.mfunc; + X foo; + foo.myp; +} diff --git a/tests/tc_access_modifiers/file2.d b/tests/tc_access_modifiers/file2.d new file mode 100644 index 0000000..87b216b --- /dev/null +++ b/tests/tc_access_modifiers/file2.d @@ -0,0 +1,9 @@ +import tc_access_modifiers.bar; + +class Subclass : Helper +{ + this() + { + this.mfield + } +} diff --git a/tests/tc_access_modifiers/run.sh b/tests/tc_access_modifiers/run.sh new file mode 100755 index 0000000..461a7d5 --- /dev/null +++ b/tests/tc_access_modifiers/run.sh @@ -0,0 +1,26 @@ +set -e +set -u + +rm -f actual1.txt actual2.txt actual3.txt actual0.txt + +../../bin/dcd-client $1 file1.d -c 137 | sed s\""$(dirname "$(pwd)")"\"\" > actual0.txt +diff actual0.txt expected0.txt + +../../bin/dcd-client $1 -I bar.d + +../../bin/dcd-client $1 file1.d -c 137 | sed s\""$(dirname "$(pwd)")"\"\" > actual1.txt +diff actual1.txt expected1.txt + +../../bin/dcd-client $1 file1.d -c 152 | sed s\""$(dirname "$(pwd)")"\"\" > actual1_1.txt +diff actual1_1.txt expected1_1.txt + +../../bin/dcd-client $1 file1.d -c 170 | sed s\""$(dirname "$(pwd)")"\"\" > actual2.txt +diff actual2.txt expected2.txt + +../../bin/dcd-client $1 file2.d -c 83 | sed s\""$(dirname "$(pwd)")"\"\" > actual3.txt +diff actual3.txt expected3.txt + +../../bin/dcd-client $1 -R bar.d + +../../bin/dcd-client $1 file1.d -c 137 | sed s\""$(dirname "$(pwd)")"\"\" > actual0.txt +diff actual0.txt expected0.txt