diff options
author | Nathan Ridge | 2014-12-21 09:38:46 +0000 |
---|---|---|
committer | Nathan Ridge | 2016-10-19 15:24:43 +0000 |
commit | fbccef3ff12c3d394e30a8bd1f1198512cff3161 (patch) | |
tree | 6822b3b4ffe99f3dec6cf9e244c3d9bfae590e35 | |
parent | ed655597538879e68ea4c25f576d8b6e1787e72c (diff) | |
download | org.eclipse.cdt-fbccef3ff12c3d394e30a8bd1f1198512cff3161.tar.gz org.eclipse.cdt-fbccef3ff12c3d394e30a8bd1f1198512cff3161.tar.xz org.eclipse.cdt-fbccef3ff12c3d394e30a8bd1f1198512cff3161.zip |
Bug 402498 - Apply declaredBefore() filtering to index bindings
Change-Id: I3086c35cf294970d4adbb65dd6aa3708710f9c02
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
7 files changed, 144 insertions, 57 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 78245d1ce22..a114b7c5e50 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -8908,6 +8908,29 @@ public class AST2TemplateTests extends AST2TestBase { assertFalse(x.getType().isSameType(CommonCPPTypes.int_)); } + // struct Cat { void meow(); }; + // struct Dog { void woof(); }; + // + // template <typename T> + // Dog bar(T); + // + // template <typename T> + // auto foo(T t) -> decltype(bar(t)); + // + // namespace N { + // class A {}; + // } + // + // Cat bar(N::A); + // + // int main() { + // auto x = foo(N::A()); + // x.woof(); + // } + public void testUnqualifiedFunctionCallInTemplate_402498d() throws Exception { + parseAndCheckBindings(); + } + // void bar(); // // template <typename T> @@ -8937,7 +8960,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testUnqualifiedFunctionCallInTemplate_458316b() throws Exception { parseAndCheckBindings(); } - + // template <typename> // struct no_type {}; // diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java index db5016d71d1..a39d330f162 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java @@ -2995,4 +2995,23 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa public void testBracedInitList_490475() throws Exception { checkBindings(); } + + // struct Cat { void meow(); }; + // struct Dog { void woof(); }; + + // template <typename T> + // Dog bar(T); + // + // template <typename T> + // auto foo(T t) -> decltype(bar(t)); + // + // Cat bar(int); + // + // int main() { + // auto x = foo(0); + // x.woof(); + // } + public void testUnqualifiedFunctionCallInTemplate_402498() throws Exception { + checkBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index abdd2fcdc88..c43def304cd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -279,6 +279,17 @@ public class CPPSemantics { // "a" => { null, "a", null } // ":: i" => { "::", "i", null } private static final Pattern QUALNAME_REGEX = Pattern.compile("^\\s*(::)?\\s*([^\\s:]+)\\s*(?:::(.*))?$"); //$NON-NLS-1$ + + // This flag controls whether name lookup is allowed to find bindings in headers + // that are not reachable via includes from the file containing the name. + // Generally this is not allowed, but certain consumers, such as IncludeOrganizer, + // need it (since the whole point of IncludeOrganizer is to find missing headers). + private static final ThreadLocal<Boolean> fAllowPromiscuousBindingResolution = new ThreadLocal<Boolean>() { + @Override + protected Boolean initialValue() { + return false; + } + }; static protected IBinding resolveBinding(IASTName name) { if (traceBindingResolution) { @@ -1958,63 +1969,76 @@ public class CPPSemantics { } } - if (pointOfDecl < 0 && nd != null) { - ASTNodeProperty prop = nd.getPropertyInParent(); - if (prop == IASTDeclarator.DECLARATOR_NAME || nd instanceof IASTDeclarator) { - // Point of declaration for a name is immediately after its complete declarator - // and before its initializer. - IASTDeclarator dtor = (IASTDeclarator)((nd instanceof IASTDeclarator) ? nd : nd.getParent()); - while (dtor.getParent() instanceof IASTDeclarator) { - dtor = (IASTDeclarator) dtor.getParent(); - } - IASTInitializer init = dtor.getInitializer(); - // [basic.scope.pdecl]/p9: The point of declaration for a template parameter - // is immediately after its complete template-parameter. - // Note: can't just check "dtor.getParent() instanceof ICPPASTTemplateParameter" - // because function parameter declarations implement ICPPASTTemplateParameter too. - boolean isTemplateParameter = dtor.getParent() instanceof ICPPASTTemplateParameter - && dtor.getParent().getPropertyInParent() == ICPPASTTemplateDeclaration.PARAMETER; - if (init != null && !isTemplateParameter) - pointOfDecl = ((ASTNode) init).getOffset() - 1; - else - pointOfDecl = ((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength(); - } else if (prop == IASTEnumerator.ENUMERATOR_NAME) { - // Point of declaration for an enumerator is immediately after it - // enumerator-definition - IASTEnumerator enumtor = (IASTEnumerator) nd.getParent(); - if (enumtor.getValue() != null) { - ASTNode exp = (ASTNode) enumtor.getValue(); - pointOfDecl = exp.getOffset() + exp.getLength(); - } else { - pointOfDecl = nd.getOffset() + nd.getLength(); - } - } else if (prop == ICPPASTUsingDeclaration.NAME) { - nd = (ASTNode) nd.getParent(); - pointOfDecl = nd.getOffset(); - } else if (prop == ICPPASTNamespaceAlias.ALIAS_NAME) { - nd = (ASTNode) nd.getParent(); - pointOfDecl = nd.getOffset() + nd.getLength(); - } else if (prop == ICPPASTAliasDeclaration.ALIAS_NAME) { - // [basic.scope.pdecl]/p3: The point of declaration of an alias or alias template - // immediately follows the type-id to which the alias refers. - ASTNode targetType = (ASTNode) ((ICPPASTAliasDeclaration) nd.getParent()).getMappingTypeId(); - pointOfDecl = targetType.getOffset() + targetType.getLength(); - } else if (prop == ICPPASTSimpleTypeTemplateParameter.PARAMETER_NAME - || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER_NAME) { - // [basic.scope.pdecl]/p9: The point of declaration for a template parameter - // is immediately after its complete template-parameter. - // Type and template template parameters are handled here; - // non-type template parameters are handled in the DECLARATOR_NAME - // case above. - nd = (ASTNode) nd.getParent(); - pointOfDecl = nd.getOffset() + nd.getLength(); - } else { - pointOfDecl = nd.getOffset() + nd.getLength(); - } + if (pointOfDecl < 0) { + if (nd != null) { + pointOfDecl = getPointOfDeclaration(nd); + } else if (obj instanceof IIndexBinding && !fAllowPromiscuousBindingResolution.get()) { + IIndexBinding indexBinding = ((IIndexBinding) obj); + if (indexBinding instanceof ICPPMethod && ((ICPPMethod) indexBinding).isImplicit()) { + return true; + } + IASTTranslationUnit tu = node.getTranslationUnit(); + IIndexFileSet indexFileSet = tu.getIndexFileSet(); + return (indexFileSet != null && indexFileSet.containsDeclaration(indexBinding)); + } } return (pointOfDecl < pointOfRef); } + private static int getPointOfDeclaration(ASTNode nd) { + ASTNodeProperty prop = nd.getPropertyInParent(); + if (prop == IASTDeclarator.DECLARATOR_NAME || nd instanceof IASTDeclarator) { + // Point of declaration for a name is immediately after its complete declarator + // and before its initializer. + IASTDeclarator dtor = (IASTDeclarator)((nd instanceof IASTDeclarator) ? nd : nd.getParent()); + while (dtor.getParent() instanceof IASTDeclarator) + dtor = (IASTDeclarator) dtor.getParent(); + IASTInitializer init = dtor.getInitializer(); + // [basic.scope.pdecl]/p9: The point of declaration for a template parameter + // is immediately after its complete template-parameter. + // Note: can't just check "dtor.getParent() instanceof ICPPASTTemplateParameter" + // because function parameter declarations implement ICPPASTTemplateParameter too. + boolean isTemplateParameter = dtor.getParent() instanceof ICPPASTTemplateParameter + && dtor.getParent().getPropertyInParent() == ICPPASTTemplateDeclaration.PARAMETER; + if (init != null && !isTemplateParameter) + return ((ASTNode) init).getOffset() - 1; + else + return ((ASTNode) dtor).getOffset() + ((ASTNode) dtor).getLength(); + } else if (prop == IASTEnumerator.ENUMERATOR_NAME) { + // Point of declaration for an enumerator is immediately after it + // enumerator-definition + IASTEnumerator enumtor = (IASTEnumerator) nd.getParent(); + if (enumtor.getValue() != null) { + ASTNode exp = (ASTNode) enumtor.getValue(); + return exp.getOffset() + exp.getLength(); + } else { + return nd.getOffset() + nd.getLength(); + } + } else if (prop == ICPPASTUsingDeclaration.NAME) { + nd = (ASTNode) nd.getParent(); + return nd.getOffset(); + } else if (prop == ICPPASTNamespaceAlias.ALIAS_NAME) { + nd = (ASTNode) nd.getParent(); + return nd.getOffset() + nd.getLength(); + } else if (prop == ICPPASTAliasDeclaration.ALIAS_NAME) { + // [basic.scope.pdecl]/p3: The point of declaration of an alias or alias template + // immediately follows the type-id to which the alias refers. + ASTNode targetType = (ASTNode) ((ICPPASTAliasDeclaration) nd.getParent()).getMappingTypeId(); + return targetType.getOffset() + targetType.getLength(); + } else if (prop == ICPPASTSimpleTypeTemplateParameter.PARAMETER_NAME + || prop == ICPPASTTemplatedTypeTemplateParameter.PARAMETER_NAME) { + // [basic.scope.pdecl]/p9: The point of declaration for a template parameter + // is immediately after its complete template-parameter. + // Type and template template parameters are handled here; + // non-type template parameters are handled in the DECLARATOR_NAME + // case above. + nd = (ASTNode) nd.getParent(); + return nd.getOffset() + nd.getLength(); + } else { + return nd.getOffset() + nd.getLength(); + } + } + private static boolean acceptDeclaredAfter(ICPPInternalBinding cpp) { try { if (cpp instanceof ICPPNamespace || cpp instanceof ICPPFunction || cpp instanceof ICPPVariable) { @@ -4222,4 +4246,11 @@ public class CPPSemantics { return binding; } + + public static void enablePromiscuousBindingResolution() { + fAllowPromiscuousBindingResolution.set(true); + } + public static void disablePromiscuousBindingResolution() { + fAllowPromiscuousBindingResolution.set(false); + } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/BasicSearchTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/BasicSearchTest.java index 5db08148128..4c1558b73b5 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/BasicSearchTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/BasicSearchTest.java @@ -315,6 +315,7 @@ public class BasicSearchTest extends BaseUITestCase { // void foo() {} + // #include "header.h" // void bar() { // foo(); // } @@ -333,6 +334,7 @@ public class BasicSearchTest extends BaseUITestCase { // void foo() {} + // #include "header.h" // void bar() {foo();foo();foo();} public void testNewResultsOnSearchAgainB() throws Exception { CSearchQuery query= makeProjectQuery("foo"); @@ -340,7 +342,7 @@ public class BasicSearchTest extends BaseUITestCase { assertOccurrences(query, 4); // whitespace s.t. new match offset is same as older - String newContent= "void bar() { foo(); }"; + String newContent= "#include \"header.h\"\nvoid bar() { foo(); }"; IFile file = fCProject.getProject().getFile(new Path("references.cpp")); file.setContents(new ByteArrayInputStream(newContent.getBytes()), IResource.FORCE, npm()); runEventQueue(1000); @@ -350,7 +352,7 @@ public class BasicSearchTest extends BaseUITestCase { assertOccurrences(query, 2); - String newContent2= "void bar() {foo(); foo();}"; + String newContent2= "#include \"header.h\"\nvoid bar() {foo(); foo();}"; file.setContents(new ByteArrayInputStream(newContent2.getBytes()), IResource.FORCE, npm()); waitForIndexer(fCProject); @@ -362,6 +364,7 @@ public class BasicSearchTest extends BaseUITestCase { // template<typename T> void f(T) {}; // template<typename T> void f(T*) {}; + // #include "header.h" // void a() { // CT<int>* r1; // CT<char>* r2; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java index c735035f10a..c3d6ec0a5f2 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java @@ -184,6 +184,7 @@ public class CPPSelectionTestsIndexer extends BaseSelectionTestsIndexer { // public: void assign(const T* s) {} // }; + // #include "testTemplateClassMethod.h" // void main() { // C<char> a; // a.assign("aaa"); @@ -1175,6 +1176,7 @@ public class CPPSelectionTestsIndexer extends BaseSelectionTestsIndexer { // T operator+(int); // }; + // #include "test.h" // void main() { // C<char> a; // a + 2; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java index 16aa93e922e..49fb6bb63ee 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java @@ -958,7 +958,15 @@ public class BindingClassifier { if (fAst == null) { fAst = node.getTranslationUnit(); } - node.accept(fBindingCollector); + try { + // Enable promiscuous binding resolution for this AST traversal, + // to allow names to be resolved even if the declarations of their + // target bindings are in a header not reachable via includes. + CPPSemantics.enablePromiscuousBindingResolution(); + node.accept(fBindingCollector); + } finally { + CPPSemantics.disablePromiscuousBindingResolution(); + } } /** diff --git a/qt/org.eclipse.cdt.qt.ui.tests/src/org/eclipse/cdt/qt/tests/QmlRegistrationTests.java b/qt/org.eclipse.cdt.qt.ui.tests/src/org/eclipse/cdt/qt/tests/QmlRegistrationTests.java index dfc1b2ad34f..975f3abf0df 100644 --- a/qt/org.eclipse.cdt.qt.ui.tests/src/org/eclipse/cdt/qt/tests/QmlRegistrationTests.java +++ b/qt/org.eclipse.cdt.qt.ui.tests/src/org/eclipse/cdt/qt/tests/QmlRegistrationTests.java @@ -92,6 +92,7 @@ public class QmlRegistrationTests extends BaseQtTestCase { } } + // #include "junit-QObject.hh" // class T; // // static void func() |