From e2cbee5c2b2dcddfff6f322bef32728df172d2af Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Mon, 18 Feb 2013 17:44:39 -0800 Subject: [PATCH 01/11] Cosmetics. --- .../parser/cpp/CPPASTBinaryExpression.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java index e69f6acad4d..f8d836931c9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java @@ -38,7 +38,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr private int op; private ICPPASTExpression operand1; private ICPPASTInitializerClause operand2; - + private ICPPEvaluation evaluation; private IASTImplicitName[] implicitNames = null; @@ -55,7 +55,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr public CPPASTBinaryExpression copy() { return copy(CopyStyle.withoutLocations); } - + @Override public CPPASTBinaryExpression copy(CopyStyle style) { CPPASTBinaryExpression copy = new CPPASTBinaryExpression(); @@ -99,7 +99,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr if (expression != null) { if (!(expression instanceof ICPPASTExpression)) throw new IllegalArgumentException(expression.getClass().getName()); - + expression.setParent(this); expression.setPropertyInParent(OPERAND_ONE); } @@ -148,7 +148,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr if (operand1 instanceof IASTBinaryExpression || operand2 instanceof IASTBinaryExpression) { return acceptWithoutRecursion(this, action); } - + if (action.shouldVisitExpressions) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; @@ -230,13 +230,13 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr if (op2 != null && !op2.accept(action)) return false; } - + if (action.shouldVisitExpressions && action.leave(expr) == ASTVisitor.PROCESS_ABORT) return false; - + stack= stack.fNext; } - + return true; } @@ -262,22 +262,22 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr return ((EvalBinary) eval).getOverload(this); return null; } - + @Override public ICPPEvaluation getEvaluation() { - if (evaluation == null) + if (evaluation == null) evaluation= computeEvaluation(); - + return evaluation; } - + private ICPPEvaluation computeEvaluation() { if (operand1 == null || operand2 == null) return EvalFixed.INCOMPLETE; - + return new EvalBinary(op, operand1.getEvaluation(), operand2.getEvaluation()); } - + @Override public IType getExpressionType() { return getEvaluation().getTypeOrFunctionSet(this); From 0ae8bcc48c74e2997ce1d3c4f13d6ebbc8148f29 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Mon, 18 Feb 2013 17:49:55 -0800 Subject: [PATCH 02/11] Bug 401093 - Expression type for pointer difference does not fit on 64bit machines --- .../org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java | 4 ++-- .../eclipse/cdt/internal/core/dom/parser/c/CVisitor.java | 2 +- .../internal/core/dom/parser/cpp/semantics/CPPVisitor.java | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index 096032fb9ab..e6631e9f890 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -7314,7 +7314,7 @@ public class AST2Tests extends AST2TestBase { parseAndCheckBindings(code, C, true); BindingAssertionHelper bh= new BindingAssertionHelper(code, false); ITypedef td= bh.assertNonProblem("ptrdiff_t", 0); - assertEquals("int", ASTTypeUtil.getType(td.getType())); + assertEquals("long int", ASTTypeUtil.getType(td.getType())); td= bh.assertNonProblem("size_t", 0); assertEquals("unsigned long int", ASTTypeUtil.getType(td.getType())); @@ -7322,7 +7322,7 @@ public class AST2Tests extends AST2TestBase { parseAndCheckBindings(code, CPP, true); bh= new BindingAssertionHelper(code, true); td= bh.assertNonProblem("ptrdiff_t", 0); - assertEquals("int", ASTTypeUtil.getType(td.getType())); + assertEquals("long int", ASTTypeUtil.getType(td.getType())); td= bh.assertNonProblem("size_t", 0); assertEquals("unsigned long int", ASTTypeUtil.getType(td.getType())); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java index d1f5cf77ea8..ec22a238aee 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java @@ -649,7 +649,7 @@ public class CVisitor extends ASTQueries { } } - return new CBasicType(Kind.eInt, 0, expr); + return new CBasicType(Kind.eInt, IBasicType.IS_LONG, expr); } static IType get_SIZE_T(IASTExpression expr) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index f5762cf74ef..d306479aaf5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -216,8 +216,9 @@ import org.eclipse.cdt.internal.core.index.IIndexScope; * Collection of methods to extract information from a C++ translation unit. */ public class CPPVisitor extends ASTQueries { - private static final CPPBasicType UNSIGNED_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED); private static final CPPBasicType INT_TYPE = new CPPBasicType(Kind.eInt, 0); + private static final CPPBasicType LONG_TYPE = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG); + private static final CPPBasicType UNSIGNED_LONG = new CPPBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED); public static final String BEGIN_STR = "begin"; //$NON-NLS-1$ public static final char[] BEGIN = BEGIN_STR.toCharArray(); @@ -225,7 +226,7 @@ public class CPPVisitor extends ASTQueries { static final String STD = "std"; //$NON-NLS-1$ private static final char[] SIZE_T = "size_t".toCharArray(); //$NON-NLS-1$ private static final char[] PTRDIFF_T = "ptrdiff_t".toCharArray(); //$NON-NLS-1$ - private static final char[] TYPE_INFO= "type_info".toCharArray(); //$NON-NLS-1$ + private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$ private static final char[] INITIALIZER_LIST = "initializer_list".toCharArray(); //$NON-NLS-1$ private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {}; public static final IASTInitializerClause[] NO_ARGS = {}; @@ -2276,7 +2277,7 @@ public class CPPVisitor extends ASTQueries { public static IType getPointerDiffType(final IASTNode point) { IType t= getStdType(point, PTRDIFF_T); - return t != null ? t : INT_TYPE; + return t != null ? t : LONG_TYPE; } private static IType getStdType(final IASTNode node, char[] name) { From 9c88bbc509e92158463ad54519763c74bf986cd2 Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Tue, 19 Feb 2013 10:50:58 -0500 Subject: [PATCH 03/11] Fix overly strict dependency in qt.core. --- qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index b014adcf875..67bb08fb6ca 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -6,7 +6,7 @@ Bundle-Version: 1.0.0.qualifier Bundle-Activator: org.eclipse.cdt.qt.core.Activator Bundle-Vendor: Eclipse CDT Require-Bundle: org.eclipse.core.runtime, - org.eclipse.core.resources;bundle-version="3.8.100", + org.eclipse.core.resources, org.eclipse.cdt.core Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy From c48e321ea3874237194f2ee4c213a2769ad04306 Mon Sep 17 00:00:00 2001 From: Andrew Gvozdev Date: Tue, 19 Feb 2013 23:00:21 -0500 Subject: [PATCH 04/11] bug 401255: LSP userdef entries: Cannot add macro after adding a workspace include path --- .../providers/LanguageSettingEntryDialog.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java index 9fd5e328b10..faa75e6c8ae 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/language/settings/providers/LanguageSettingEntryDialog.java @@ -489,21 +489,25 @@ public class LanguageSettingEntryDialog extends AbstractPropertyDialog { inputValue.setEnabled(isMacroSelected); - int indexPathKind = comboPathCategory.getSelectionIndex(); - boolean isProjectSelected = (indexPathKind == COMBO_PATH_INDEX_PROJECT); - boolean isWorkspaceSelected = (indexPathKind == COMBO_PATH_INDEX_WORKSPACE); - boolean isFilesystemSelected = (indexPathKind == COMBO_PATH_INDEX_FILESYSTEM); - - String path = inputName.getText().trim(); - if (path.isEmpty()) { - buttonOk.setEnabled(false); + if (isMacroSelected) { + buttonOk.setEnabled(!inputName.getText().trim().isEmpty()); } else { - buttonOk.setEnabled((isProjectSelected && !path.startsWith(SLASH)) || - (isWorkspaceSelected && path.startsWith(SLASH)) || isFilesystemSelected); + int indexPathKind = comboPathCategory.getSelectionIndex(); + boolean isProjectSelected = (indexPathKind == COMBO_PATH_INDEX_PROJECT); + boolean isWorkspaceSelected = (indexPathKind == COMBO_PATH_INDEX_WORKSPACE); + boolean isFilesystemSelected = (indexPathKind == COMBO_PATH_INDEX_FILESYSTEM); + + String path = inputName.getText().trim(); + if (path.isEmpty()) { + buttonOk.setEnabled(false); + } else { + buttonOk.setEnabled((isProjectSelected && !path.startsWith(SLASH)) || + (isWorkspaceSelected && path.startsWith(SLASH)) || isFilesystemSelected); + } + + buttonVars.setEnabled(isFilesystemSelected); } - buttonVars.setEnabled(isFilesystemSelected); - compositeArea.layout(true); } From 81885d232fec146ec4c1d6c1fbac552daff416ea Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Sun, 17 Feb 2013 20:28:11 -0500 Subject: [PATCH 05/11] Bug 401024 - Error involving variadic templates Change-Id: Ic5e0b3176e87e6dcecfb528367ce5f8eea4760c1 Reviewed-on: https://git.eclipse.org/r/10426 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../parser/tests/ast2/AST2TemplateTests.java | 49 +++++++++++++++++-- .../eclipse/cdt/core/dom/ast/ASTTypeUtil.java | 2 + 2 files changed, 46 insertions(+), 5 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 31e4ef589b2..30a2844295d 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 @@ -4509,25 +4509,25 @@ public class AST2TemplateTests extends AST2TestBase { parseAndCheckBindings(code); BindingAssertionHelper bh= new BindingAssertionHelper(code, CPP); ICPPFunctionTemplate f= bh.assertNonProblem("f1", 2); - assertEquals("void (int (*)(#0 ...))", ASTTypeUtil.getType(f.getType(), true)); + assertEquals("void (int (*)(#0(...) ...))", ASTTypeUtil.getType(f.getType(), true)); assertFalse(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f2", 2); - assertEquals("void (int (* ...)(#0, int))", ASTTypeUtil.getType(f.getType(), true)); + assertEquals("void (int (* ...)(#0(...), int))", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f3", 2); - assertEquals("void (#0 (* ...)())", ASTTypeUtil.getType(f.getType(), true)); + assertEquals("void (#0(...) (* ...)())", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f4", 2); assertEquals("void (int (& ...)[3 *0 0])", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f5", 2); - assertEquals("void (#0 ...)", ASTTypeUtil.getType(f.getType(), true)); + assertEquals("void (#0(...) ...)", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f6", 2); assertEquals("void (#0, ...)", ASTTypeUtil.getType(f.getType(), true)); assertFalse(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f7", 2); - assertEquals("#0 ...", ASTTypeUtil.getType(f.getExceptionSpecification()[0], true)); + assertEquals("#0(...) ...", ASTTypeUtil.getType(f.getExceptionSpecification()[0], true)); } // template class C1 {}; @@ -7165,4 +7165,43 @@ public class AST2TemplateTests extends AST2TestBase { public void testDependentExpressionInvolvingFieldInNestedClass_399362() throws Exception { parseAndCheckBindings(); } + + // template + // struct remove_reference { + // typedef _Tp type; + // }; + // template + // struct A {}; + // template + // struct waldo { + // typedef typename remove_reference::type src_t; + // typedef A type; + // }; + // template + // struct ice_or { + // static const bool value = First; + // }; + // template + // struct is_waldo { + // static const bool value = false; + // }; + // template + // struct contains_waldo { + // static const bool value = ice_or::type>::value...>::value; + // }; + // template + // struct S {}; + // struct Cat { + // void meow(); + // }; + // template <> + // struct S { + // typedef Cat type; + // }; + // int main() { + // S::value>::type t; + // } + public void testVariadicTemplates_401024() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java index 5a254287247..fd1a93fe467 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java @@ -424,6 +424,8 @@ public class ASTTypeUtil { if (normalize) { result.append('#'); result.append(Integer.toString(type.getParameterID(), 16)); + if (type.isParameterPack()) + result.append("(...)"); //$NON-NLS-1$ } else { result.append(type.getName()); } From 2279927623d6d393db81fba7ceca12f047935bf8 Mon Sep 17 00:00:00 2001 From: Andrew Eidsness Date: Tue, 19 Feb 2013 20:40:15 -0500 Subject: [PATCH 06/11] Bug 400020: Allow tagging of IBindings This new extension point allows contributors to put their own information into the PDOM and to later retrieve it for their own purposes. There are many details in the bug. The idea is that contributors provide an implementation of IBindingTagger, which is given a chance to examine IBindings when they are created. The ITagWriter interface allows the contributor to create a new tag which can then have data written to it. The ITagService interface (accessible from CCorePlugin.getTagService() provides a way for the contributor to later get an instance of ITagReader to retrieve tags from bindings. ITags are copied to the PDOM when the associated binding is persisteed. Contributors use a unique id (based on their plugin id), so that multiple contributors are able to independently tag a given binding. In-memory tags are not cached. I've done some timing tests using my sample implementation and found no measurable difference. The full log lines look like: !MESSAGE Indexed 'simple-01' (2 sources, 184 headers) in sec: 21,550 declarations; 35,394 references; 0 unresolved inclusions; 1 syntax errors; 0 unresolved names (0.00%) I did 5 tests using the current master (no tagging-related code), the times were: 18.86 sec 9.17 sec 5.91 sec 4.79 sec 4.83 sec And then I ran the same sequence of tests using the code in this commit: 18.73 sec 9.39 sec 6.50 sec 4.78 sec 5.27 sec If performance does become a problem, then caching could be introduced with a new implementation of ITaggableService. The two problems are finding a key other than the identity of the IBinding (since IBindings are re-created often) and properly evicting stale entries when the binding is no longer valid. The process of copying tags from an in-memory IBinding to a PDOMBinding, is a synchronization. This means that tags that are no longer applicable, will be removed from the persistent store. While developing this I found that PDOMBindings are not deleted from the Database (only the names that reference them are deleted), so there is no provision for deleting all tags at once. New database locks are not needed. By the time the persistent tags are accessed, higher levels of code have already taken a read or write lock as appropriate. There are new unit tests covering the changes to the PDOM. Change-Id: I8da1bf5eeba7e1fc2ca7ec308ed8e212629986a4 Reviewed-on: https://git.eclipse.org/r/10407 IP-Clean: Doug Schaefer Tested-by: Doug Schaefer Reviewed-by: Doug Schaefer --- .../pdom/tests/PDOMStringSetTests.java | 78 +++++ .../pdom/tests/PDOMTagIndexTests.java | 135 ++++++++ .../cdt/internal/pdom/tests/PDOMTests.java | 4 +- .../org.eclipse.cdt.core/META-INF/MANIFEST.MF | 4 + .../cdt/core/dom/ast/tag/IBindingTagger.java | 34 ++ .../eclipse/cdt/core/dom/ast/tag/ITag.java | 41 +++ .../cdt/core/dom/ast/tag/ITagReader.java | 33 ++ .../cdt/core/dom/ast/tag/ITagService.java | 30 ++ .../cdt/core/dom/ast/tag/ITagWriter.java | 34 ++ .../cdt/core/dom/ast/tag/IWritableTag.java | 31 ++ .../core/dom/ast/tag/NonCachedTaggable.java | 96 ++++++ .../cdt/internal/core/dom/ast/tag/Tag.java | 78 +++++ .../internal/core/dom/ast/tag/TagManager.java | 107 ++++++ .../internal/core/dom/ast/tag/TagService.java | 35 ++ .../core/dom/ast/tag/TaggerDescriptor.java | 202 ++++++++++++ .../dom/parser/cpp/semantics/CPPVisitor.java | 6 +- .../core/pdom/AbstractIndexerTask.java | 5 + .../eclipse/cdt/internal/core/pdom/PDOM.java | 19 +- .../internal/core/pdom/db/PDOMStringSet.java | 205 ++++++++++++ .../internal/core/pdom/dom/PDOMBinding.java | 10 + .../core/pdom/dom/c/PDOMCLinkage.java | 14 +- .../core/pdom/dom/cpp/PDOMCPPLinkage.java | 24 +- .../internal/core/pdom/tag/BTreeIterable.java | 78 +++++ .../cdt/internal/core/pdom/tag/PDOMTag.java | 312 ++++++++++++++++++ .../internal/core/pdom/tag/PDOMTagIndex.java | 279 ++++++++++++++++ .../core/pdom/tag/PDOMTagSynchronizer.java | 104 ++++++ .../internal/core/pdom/tag/PDOMTaggable.java | 51 +++ core/org.eclipse.cdt.core/plugin.properties | 1 + core/org.eclipse.cdt.core/plugin.xml | 1 + core/org.eclipse.cdt.core/schema/tagger.exsd | 139 ++++++++ .../src/org/eclipse/cdt/core/CCorePlugin.java | 11 + 31 files changed, 2190 insertions(+), 11 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java create mode 100644 core/org.eclipse.cdt.core/schema/tagger.exsd diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java new file mode 100644 index 00000000000..1ba161f81ad --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMStringSetTests.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.pdom.tests; + +import java.io.File; + +import junit.framework.Test; + +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.PDOMStringSet; + +// copy/pasted from BTreeTests +public class PDOMStringSetTests extends BaseTestCase +{ + protected File dbFile; + protected Database db; + protected PDOMStringSet stringSet; + protected int rootRecord; + + public static Test suite() + { + return suite( PDOMStringSetTests.class ); + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + dbFile = File.createTempFile( "pdomstringsettest", "db" ); + db = new Database( dbFile, new ChunkCache(), 0, false ); + db.setExclusiveLock(); + rootRecord = Database.DATA_AREA; + stringSet = new PDOMStringSet( db, rootRecord ); + } + + @Override + protected void tearDown() throws Exception + { + db.close(); + dbFile.deleteOnExit(); + + super.tearDown(); + } + + // Quick tests to exercise the basic functionality. + public void testInterface() throws Exception + { + long val1_rec_a = stringSet.add( "val1" ); + long val2_rec_a = stringSet.add( "val2" ); + long val1_rec_b = stringSet.add( "val1" ); + assertTrue( val1_rec_a != 0 ); + assertTrue( val2_rec_a != 0 ); + assertEquals( val1_rec_a, val1_rec_b ); + + long val1_find = stringSet.find( "val1" ); + long val2_find = stringSet.find( "val2" ); + assertEquals( val1_rec_a, val1_find ); + assertEquals( val2_rec_a, val2_find ); + + long val1_rm = stringSet.remove( "val1" ); + assertEquals( val1_rec_a, val1_rm ); + assertEquals( 0, stringSet.find( "val1" ) ); + assertEquals( val2_rec_a, stringSet.find( "val2" ) ); + + stringSet.clearCaches(); + assertEquals( val2_rec_a, stringSet.find( "val2" ) ); + assertEquals( 0, stringSet.find( "val1" ) ); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java new file mode 100644 index 00000000000..34df365853e --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTagIndexTests.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.pdom.tests; + +import java.io.File; +import java.util.Arrays; + +import junit.framework.Test; + +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.index.IIndexLocationConverter; +import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.cdt.internal.core.dom.ast.tag.Tag; +import org.eclipse.cdt.internal.core.pdom.PDOM; +import org.eclipse.cdt.internal.core.pdom.WritablePDOM; +import org.eclipse.cdt.internal.core.pdom.tag.PDOMTag; +import org.eclipse.cdt.internal.core.pdom.tag.PDOMTagIndex; + +// copy/pasted from BTreeTests +public class PDOMTagIndexTests extends BaseTestCase +{ + private PDOM pdom; + + public static Test suite() + { + return suite( PDOMTagIndexTests.class ); + } + + private static class MockIndexLocationConverter implements IIndexLocationConverter + { + @Override public IIndexFileLocation fromInternalFormat( String raw ) { return null; } + @Override public String toInternalFormat( IIndexFileLocation location ) { return null; } + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + File tmpFile = File.createTempFile( getClass().getSimpleName() + '.' + Double.toString( Math.random() ).substring( 2 ), null ); + pdom = new WritablePDOM( tmpFile, new MockIndexLocationConverter(), LanguageManager.getInstance().getPDOMLinkageFactoryMappings() ); + } + + @Override + protected void tearDown() throws Exception + { + pdom.close(); + super.tearDown(); + } + + // return the nearest valid record that is less than the specified base + private static long lastRecordBase = 1000; + private static long computeValidRecord() + { + lastRecordBase += 1000; + return ( lastRecordBase & ~7L ) | 2; + } + + // A quick sanity test to confirm basic functionality. + public void testSimple() throws Exception + { + String tagger = "tagger_a"; + long rec = computeValidRecord(); + + assertNotNull( PDOMTagIndex.createTag( pdom, rec, tagger, 1 ) ); + assertNotNull( PDOMTagIndex.getTag( pdom, rec, tagger ) ); + } + + public void testMultipleTaggers() throws Exception + { + String tagger_a = "tagger_a"; + String tagger_b = "tagger_b"; + long rec1 = computeValidRecord(); + long rec2 = computeValidRecord(); + + assertNotNull( PDOMTagIndex.createTag( pdom, rec1, tagger_a, 1 ) ); + assertNotNull( PDOMTagIndex.createTag( pdom, rec1, tagger_b, 1 ) ); + assertNotNull( PDOMTagIndex.createTag( pdom, rec2, tagger_a, 1 ) ); + + assertNotNull( PDOMTagIndex.getTag( pdom, rec2, tagger_a ) ); + assertNull( PDOMTagIndex.getTag( pdom, rec2, tagger_b ) ); + + Iterable tags1 = PDOMTagIndex.getTags( pdom, rec1 ); + int tag_count = 0; + for( ITag tag : tags1 ) + { + ++tag_count; + assertTrue( tag.getTaggerId().equals( tagger_a ) || tag.getTaggerId().equals( tagger_b ) ); + assertEquals( 1, tag.getDataLen() ); + } + assertEquals( 2, tag_count ); + } + + public void testReplaceTags() throws Exception + { + String tagger_a = "tagger_a"; + String tagger_b = "tagger_b"; + long rec = computeValidRecord(); + + ITag taga = PDOMTagIndex.createTag( pdom, rec, tagger_a, 2 ); + assertNotNull( taga ); + assertTrue( taga instanceof PDOMTag ); + PDOMTag taga_pdom = (PDOMTag)taga; + ITag tagb = PDOMTagIndex.createTag( pdom, rec, tagger_a, 2 ); + assertNotNull( tagb ); + + // replacement should delete tags for taggers that are no longer present and shorter tags + // should be modified in place + PDOMTagIndex.setTags( pdom, rec, Arrays.asList( new Tag( tagger_a, 1 ) ) ); + assertNull( PDOMTagIndex.getTag( pdom, rec, tagger_b ) ); + ITag shorter_ = PDOMTagIndex.getTag( pdom, rec, tagger_a ); + assertNotNull( shorter_ ); + assertTrue( shorter_ instanceof PDOMTag ); + PDOMTag shorter_pdom = (PDOMTag)shorter_; + assertEquals( taga_pdom.getRecord(), shorter_pdom.getRecord() ); + + // longer tags should create a new record + PDOMTagIndex.setTags( pdom, rec, Arrays.asList( new Tag( tagger_a, 4 ) ) ); + ITag longer_ = PDOMTagIndex.getTag( pdom, rec, tagger_a ); + assertNotNull( longer_ ); + assertTrue( longer_ instanceof PDOMTag ); + PDOMTag longer_pdom = (PDOMTag)longer_; + assertTrue( taga_pdom.getRecord() != longer_pdom.getRecord() ); + + // TODO figure out how to confirm that the original tag was free'd + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java index f244ec3925c..3640bbe7339 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/PDOMTests.java @@ -38,7 +38,9 @@ public class PDOMTests extends TestSuite { suite.addTest(OverloadsWithinSingleTUTests.suite()); suite.addTest(OverloadsWithinCommonHeaderTests.suite()); suite.addTest(BTreeTests.suite()); - suite.addTest(FilesOnReindexTests.suite()); + suite.addTest(PDOMStringSetTests.suite()); + suite.addTest(PDOMTagIndexTests.suite()); + suite.addTest(FilesOnReindexTests.suite()); suite.addTest(GeneratePDOMApplicationTest.suite()); suite.addTest(CPPFieldTests.suite()); diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index 9130967645b..b4de8014640 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -16,6 +16,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.core.dom.ast.gnu, org.eclipse.cdt.core.dom.ast.gnu.c, org.eclipse.cdt.core.dom.ast.gnu.cpp, + org.eclipse.cdt.core.dom.ast.tag, org.eclipse.cdt.core.dom.parser, org.eclipse.cdt.core.dom.parser.c, org.eclipse.cdt.core.dom.parser.cpp, @@ -52,6 +53,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.internal.core.browser;x-friends:="org.eclipse.cdt.ui", org.eclipse.cdt.internal.core.cdtvariables;x-internal:=true, org.eclipse.cdt.internal.core.dom;x-internal:=true, + org.eclipse.cdt.internal.core.dom.ast.tag;x-internal:=true, org.eclipse.cdt.internal.core.dom.parser;x-friends:="org.eclipse.cdt.ui", org.eclipse.cdt.internal.core.dom.parser.c;x-friends:="org.eclipse.cdt.ui", org.eclipse.cdt.internal.core.dom.parser.cpp;x-friends:="org.eclipse.cdt.ui", @@ -84,6 +86,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.internal.core.pdom.dom.cpp;x-internal:=true, org.eclipse.cdt.internal.core.pdom.export;x-internal:=true, org.eclipse.cdt.internal.core.pdom.indexer;x-friends:="org.eclipse.cdt.ui", + org.eclipse.cdt.internal.core.pdom.tag;x-internal:=true, org.eclipse.cdt.internal.core.resources;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.make.core,org.eclipse.cdt.codan.ui.cxx", org.eclipse.cdt.internal.core.settings.model;x-internal:=true, org.eclipse.cdt.internal.core.util;x-internal:=true, @@ -111,6 +114,7 @@ Export-Package: org.eclipse.cdt.core, org.eclipse.cdt.utils.xcoff, org.eclipse.cdt.utils.xcoff.parser Require-Bundle: org.eclipse.core.contenttype;bundle-version="[3.3.0,4.0.0)", + org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.filebuffers;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.filesystem;bundle-version="[1.1.0,2.0.0)", org.eclipse.core.resources;bundle-version="[3.2.0,4.0.0)", diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java new file mode 100644 index 00000000000..e5a31f14b72 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IBindingTagger.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; + +/** + * Implementations are contributed with the org.eclipse.cdt.core.tagger extension-point. The implementation + * is responsible for populating the tag's data using a given input binding. + * + * @see #process(ITagWriter, IBinding, IASTName) + * @since 5.5 + */ +public interface IBindingTagger +{ + /** + * Examine the given input binding to decide if a tag should be created. Use the given tagWriter + * to create data if needed. Return the tag if one was created and null otherwise. A tagger (as + * identified by it's unique id string) is allowed to create only one tag for each binding. + * + * @param tagWriter the writer to use for creating new tags + * @param binding the binding to examine when populating the tag (if needed) + * @param ast the AST name from which the binding was created + * @return the tag if one was created and null otherwise + */ + public ITag process( ITagWriter tagWriter, IBinding binding, IASTName ast ); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java new file mode 100644 index 00000000000..00c0ec9fcf5 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITag.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + +/** + * Tags are used to annotate {@link ITagReader}'s with extra information. They are created + * by implementations of {@link IBindingTagger} which are contributed using the + * org.eclipse.cdt.core.tagger extension point. The base tag interface is read-only, it + * is extended by the writable {@link IWritableTag}. + * + * @see IBindingTagger + * @see ITagReader + * @see IWritableTag + * @since 5.5 + */ +public interface ITag +{ + /** A constant that is returned to indicate a read failure. */ + public static final int Fail = -1; + + /** Return the number of bytes in the tag's data payload. */ + public int getDataLen(); + + /** Return the globally unique id of the tagger that created the receiver. */ + public String getTaggerId(); + + /** Return the byte from the specified offset or {@link #Fail} on failure. */ + public int getByte( int offset ); + + /** Return the specified number of bytes from the specified offset. Specify len of -1 to read all + * bytes from the specified offset to the end of the payload. Return null on failure. */ + public byte[] getBytes( int offset, int len ); + + // TODO read methods for all the other types +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java new file mode 100644 index 00000000000..fb9d6ca3f58 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagReader.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + + +/** + * An interface that provides read-only access to the tags associated with a particular binding. + * + * @see ITag + * @see ITagService + * @since 5.5 + */ +public interface ITagReader +{ + /** + * Look for a tag for the receiver, returns null if there is no such tag. + * + * @param id A string that uniquely identifies the tag to be returned. This value was provided by the contributor + * when the tag was created (see {@link ITagWriter#createTag(String, int)}). + */ + public ITag getTag( String id ); + + /** + * Return all tags known to the receiver. Does not return null. + */ + public Iterable getTags(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java new file mode 100644 index 00000000000..05e12af7a4b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagService.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + +import org.eclipse.cdt.core.dom.ast.IBinding; + +/** + * Provides ITagReaders for specific bindings. The kind of the reader will vary based on + * the kind of the input binding. + * + * @see ITag + * @see ITagReader + * @since 5.5 + */ +public interface ITagService +{ + /** + * Finds or creates a tag reader for the specified binding or null if a reader cannot + * be associated with this binding. + * + * @param binding could be null + */ + public ITagReader findTagReader( IBinding binding ); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java new file mode 100644 index 00000000000..34849ba59fe --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/ITagWriter.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + +/** + * An interface that allows tag creation and modification. + * + * @see ITag + * @see ITagService + * @since 5.5 + */ +public interface ITagWriter +{ + /** + * Create and return a new tag for the receiver. E.g., if this writer is associated with a persistent binding, + * then returned tag will read and write from the PDOM database. + * + * @param id A string that uniquely identifies the tag to be returned. This value will be used by the contributor + * when to find the tag (see {@link ITagReader#getTag(String)}). + * @param len The number of bytes that should be allocated to store the tag's data. + */ + public IWritableTag createTag( String id, int len ); + + /** + * Sets the receiver's tags to only the ones provided. Deletes existing tags that are not in the argument list. + */ + public boolean setTags( Iterable tags ); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java new file mode 100644 index 00000000000..bb6a8eecb33 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/tag/IWritableTag.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.core.dom.ast.tag; + +/** + * Tags are used to annotate {@link ITagWriter}'s with extra information. They are created + * by implementations of {@link IBindingTagger} which are contributed using the + * org.eclipse.cdt.core.tagger extension point. + * + * @see IBindingTagger + * @see ITagReader + * @see ITagWriter + * @since 5.5 + */ +public interface IWritableTag extends ITag +{ + /** Write the given byte to the given offset in the tag. Return true if successful and false otherwise. */ + public boolean putByte( int offset, byte data ); + + /** Write the argument buffer into the receiver's payload starting at the specified offset. Write the specified + * number of bytes or the full buffer when len is -1. Return true if successful and false otherwise. */ + public boolean putBytes( int offset, byte data[], int len ); + + // TODO write for all types +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java new file mode 100644 index 00000000000..c74ea936709 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/NonCachedTaggable.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.dom.ast.tag; + +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; + +public class NonCachedTaggable implements ITagReader, ITagWriter +{ + private final IBinding binding; + private IASTName ast; + + public NonCachedTaggable( IBinding binding ) + { + this.binding = binding; + } + + @Override + public IWritableTag createTag( String id, int len ) + { + return new Tag( id, len ); + } + + @Override + public ITag getTag( String id ) + { + return TagManager.getInstance().process( id, this, binding, getAST() ); + } + + @Override + public Iterable getTags() + { + return TagManager.getInstance().process( this, binding, getAST() ); + } + + @Override + public boolean setTags( Iterable tags ) + { + // this non-caching implementation has nothing to set, the tags will be regenerated + // when they are queried + return true; + } + + private IASTName getAST() + { + if( ast != null ) + return ast; + + if( ! ( binding instanceof ICPPInternalBinding ) ) + return null; + + IASTNode node = getPhysicalNode( (ICPPInternalBinding)binding ); + if( node == null ) + return null; + + return ast = getName( node ); + } + + private static IASTNode getPhysicalNode( ICPPInternalBinding binding ) + { + IASTNode node = binding.getDefinition(); + if( node != null ) + return node; + + IASTNode[] nodes = binding.getDeclarations(); + if( nodes == null + || nodes.length <= 0 ) + return null; + return nodes[0]; + } + + private static IASTName getName( IASTNode node ) + { + if( node instanceof IASTName ) + return (IASTName)node; + if( node instanceof ICPPASTCompositeTypeSpecifier ) + return ( (ICPPASTCompositeTypeSpecifier)node ).getName(); + if( node instanceof IASTDeclarator ) + return ( (IASTDeclarator)node ).getName(); + return null; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java new file mode 100644 index 00000000000..d0979f421dd --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/Tag.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.dom.ast.tag; + +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; + +/** + * A trivial implementation that stores all data in memory. + * + * @see NonCachedTaggable + */ +public class Tag implements IWritableTag +{ + private final String taggerId; + private final byte[] buff; + + public Tag( String taggerId, int dataLen ) + { + this.taggerId = taggerId; + this.buff = new byte[dataLen]; + } + + @Override public String getTaggerId() { return taggerId; } + @Override public int getDataLen() { return buff.length; } + + private boolean isInBounds( int offset, int len ) + { + return offset >= 0 + && offset < buff.length + && ( offset + len ) <= buff.length; + } + + @Override + public boolean putByte( int offset, byte b ) + { + if( ! isInBounds( offset, 1 ) ) + return false; + + buff[offset] = b; + return true; + } + + @Override + public boolean putBytes( int offset, byte[] data, int len ) + { + len = len >= 0 ? len : data.length; + if( ! isInBounds( offset, len ) ) + return false; + + System.arraycopy( data, 0, buff, offset, len ); + return true; + } + + @Override + public int getByte( int offset ) + { + return isInBounds( offset, 1 ) ? buff[offset] : ITag.Fail; + } + + @Override + public byte[] getBytes( int offset, int len ) + { + len = len >= 0 ? len : buff.length - offset; + if( ! isInBounds( offset, len ) ) + return null; + + byte[] data = new byte[len]; + System.arraycopy( buff, offset, data, 0, len ); + return data; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java new file mode 100644 index 00000000000..c302fae7e28 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagManager.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.dom.ast.tag; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding; +import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; + +public class TagManager +{ + private static TagManager INSTANCE; + + private Map taggers; + + public static TagManager getInstance() + { + if( INSTANCE == null ) + INSTANCE = new TagManager(); + return INSTANCE; + } + + private TagManager() + { + taggers = loadExtensions(); + } + + private static final String ExtensionPoint = "tagger"; //$NON-NLS-1$ + + private static Map loadExtensions() + { + Map taggers = new HashMap(); + + // load the extensions + IConfigurationElement[] elements + = Platform.getExtensionRegistry().getConfigurationElementsFor( CCorePlugin.PLUGIN_ID, ExtensionPoint ); + for (IConfigurationElement element : elements) + { + TaggerDescriptor desc = new TaggerDescriptor( element ); + taggers.put( desc.getId(), desc ); + } + + return taggers; + } + + /** Provide an opportunity for the specified tagger to process the given values. The tagger will only + * run if its enablement expression returns true for the arguments. */ + public ITag process( String taggerId, ITagWriter tagWriter, IBinding binding, IASTName ast ) + { + TaggerDescriptor desc = taggers.get( taggerId ); + if( desc == null ) + return null; + + IBindingTagger tagger = desc.getBindingTaggerFor( binding, ast ); + return tagger == null ? null : tagger.process( tagWriter, binding, ast ); + } + + /** Provide an opportunity for all enabled taggers to process the given values. */ + public Iterable process( ITagWriter tagWriter, IBinding binding, IASTName ast ) + { + List tags = new LinkedList(); + for( TaggerDescriptor desc : taggers.values() ) + { + IBindingTagger tagger = desc.getBindingTaggerFor( binding, ast ); + if( tagger != null ) + { + ITag tag = tagger.process( tagWriter, binding, ast ); + if( tag != null ) + tags.add( tag ); + } + } + + return tags; + } + + /** Add or remove tags from the destination to ensure that it has the same tag information as the source. */ + public void syncTags( IPDOMBinding dst, IBinding src ) + { + if( dst == null ) + return; + + ITagReader tagReader = CCorePlugin.getTagService().findTagReader( src ); + if( tagReader == null ) + return; + + ITagWriter tagWriter = new PDOMTaggable( dst.getPDOM(), dst.getRecord() ); + tagWriter.setTags( tagReader.getTags() ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java new file mode 100644 index 00000000000..dad4d60895c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TagService.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.dom.ast.tag; + +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.dom.ast.tag.ITagService; + +public class TagService implements ITagService +{ + /** + * First gives the IBinding instance a chance to convert itself, by calling IAdaptable#getAdapter( ITagReader.class ) + * on the binding. If the binding doesn't provide an implementation then a simple, in-memory, non-cached + * implementation is created and returned. + */ + @Override + public ITagReader findTagReader( IBinding binding ) + { + if( binding == null ) + return null; + + // let the binding adapt to its own tag reader + ITagReader tagReader = (ITagReader)binding.getAdapter( ITagReader.class ); + if( tagReader != null ) + return tagReader; + + return new NonCachedTaggable( binding ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java new file mode 100644 index 00000000000..c0386142f80 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/ast/tag/TaggerDescriptor.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.dom.ast.tag; + +import java.util.Arrays; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.expressions.ExpressionTagNames; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; + +/** + * Internal container for extensions of org.eclipse.cdt.core.tagger. The implementation of the + * tagger is instantiated only after checking the enablement expression (if present) for the + * specified binding. This avoids activating the contributing plugin until it is actually needed. + */ +public class TaggerDescriptor +{ + private static final String Attr_LocalId = "local-id"; //$NON-NLS-1$ + private static final String Attr_Class = "class"; //$NON-NLS-1$ + + private final IConfigurationElement element; + private final Expression enablementExpression; + private Boolean fStatus = null; + + private String id; + private IBindingTagger tagger; + + private static final String Var_projectNature = "projectNatures"; //$NON-NLS-1$ + private static final String Var_languageId = "languageId"; //$NON-NLS-1$ + + /** An empty implementation of the tagger used as a placeholder in descriptors that are unable to + * load the contributed class. */ + private static final IBindingTagger NullTagger = new IBindingTagger() + { + @Override public ITag process(ITagWriter tagWriter, IBinding binding, IASTName ast) { return null; } + }; + + public TaggerDescriptor( IConfigurationElement element ) + { + this.element = element; + + Expression expr = null; + IConfigurationElement[] children = element.getChildren( ExpressionTagNames.ENABLEMENT ); + switch (children.length) { + case 0: + fStatus = Boolean.TRUE; + break; + case 1: + try { + ExpressionConverter parser = ExpressionConverter.getDefault(); + expr = parser.perform( children[0] ); + } catch (CoreException e) { + CCorePlugin.log( "Error in enablement expression of " + id, e ); //$NON-NLS-1$ + } + break; + default: + CCorePlugin.log( "Too many enablement expressions for " + id ); //$NON-NLS-1$ + fStatus = Boolean.FALSE; + break; + } + enablementExpression = expr; + } + + public String getId() + { + if( id != null ) + return id; + + String globalId = element.getContributor().getName(); + String localId = element.getAttribute( Attr_LocalId ); + + // there must be a valid local id + if( localId == null ) + { + String extId = element.getDeclaringExtension().getSimpleIdentifier(); + CCorePlugin.log( "Invalid extension " + globalId + '.' + extId + " must provide tagger's local-id" ); //$NON-NLS-1$ //$NON-NLS-2$ + return null; + } + + // the extension should not include the plugin id, but return immediately if it does + if( localId.startsWith( globalId ) + && localId.length() > globalId.length() ) + return localId; + + // make sure the local id has real content + if( localId.isEmpty() ) + { + String extId = element.getDeclaringExtension().getSimpleIdentifier(); + CCorePlugin.log( "Invalid extension " + globalId + '.' + extId + " must provide value for tagger's local-id" ); //$NON-NLS-1$ //$NON-NLS-2$ + return null; + } + + // otherwise prepend with the globalId, and ensure a dot between them + if( localId.charAt( 0 ) == '.' ) + return globalId + localId; + return globalId + '.' + localId; + } + + private boolean matches( ITranslationUnit tu ) + { + // if the enablement expression is missing or structurally invalid, then return immediately + if( fStatus != null ) + return fStatus.booleanValue(); + + // if there is no tu, then the enablement expression cannot be evaluated, assume that all taggers + // are needed + if( tu == null ) + return true; + + if( enablementExpression != null ) + try + { + IProject project = null; + ICProject cProject = tu.getCProject(); + if( cProject != null ) + project = cProject.getProject(); + + EvaluationContext evalContext = new EvaluationContext( null, project ); + + // if the project is not accessible, then only taggers that don't care about it will + // get a chance to run + if( project != null ) + { + String[] natures = project.getDescription().getNatureIds(); + evalContext.addVariable( Var_projectNature, Arrays.asList( natures ) ); + } + + ILanguage language = tu.getLanguage(); + if( language != null ) + evalContext.addVariable( Var_languageId, language.getId() ); + + return enablementExpression.evaluate( evalContext ) == EvaluationResult.TRUE; + } + catch( CoreException e ) + { + CCorePlugin.log( "Error while evaluating enablement expression for " + id, e ); //$NON-NLS-1$ + } + + fStatus = Boolean.FALSE; + return false; + } + + private IBindingTagger getTagger() + { + if( tagger == null ) + synchronized( this ) + { + if( tagger == null ) + { + try { tagger = (IBindingTagger)element.createExecutableExtension( Attr_Class ); } + catch( CoreException e ) + { + String id = element.getDeclaringExtension().getNamespaceIdentifier() + '.' + + element.getDeclaringExtension().getSimpleIdentifier(); + CCorePlugin.log( "Error in class attribute of " + id, e ); //$NON-NLS-1$ + + // mark the tagger with an empty implementation to prevent future load attempts + tagger = NullTagger; + } + } + } + + return tagger; + } + + // Activates the plugin if needed. + public IBindingTagger getBindingTaggerFor( IBinding binding, IASTName ast ) + { + // If there isn't an ast with an AST-TU accessible, then there is no way to defer processing, + // just return the tagger and let it try to sort things out. E.g., this happens for built-in + // things. + if( ast == null ) + return getTagger(); + IASTTranslationUnit astTU = ast.getTranslationUnit(); + if( astTU == null ) + return getTagger(); + + // Otherwise evaluate the enablement expression for this TU + return matches( astTU.getOriginatingTranslationUnit() ) ? getTagger() : null; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index d306479aaf5..403516e53a8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -340,10 +340,10 @@ public class CPPVisitor extends ASTQueries { return false; } } - + if (inScope == null) return false; - + IBinding pb= names[names.length-2].resolvePreBinding(); if (pb instanceof IProblemBinding) return false; @@ -357,7 +357,7 @@ public class CPPVisitor extends ASTQueries { } else if (pb instanceof ICPPNamespace) { scope= ((ICPPNamespace)pb).getNamespaceScope(); } - + return scope == inScope; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java index cf628dbf052..df417262095 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java @@ -41,6 +41,7 @@ import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.AbstractLanguage; import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IScannerInfo; @@ -48,6 +49,7 @@ import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.ParserUtil; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; +import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; import org.eclipse.cdt.internal.core.index.FileContentKey; import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; @@ -1004,6 +1006,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter { IASTTranslationUnit ast= createAST(lang, codeReader, scanInfo, isSource, fASTOptions, ctx, pm); fStatistics.fParsingTime += System.currentTimeMillis() - start; if (ast != null) { + // Give the new AST-TU a chance to recognize its translation unit before it is written + // to the index. + ( (ASTTranslationUnit)ast ).setOriginatingTranslationUnit( (ITranslationUnit)tu ); writeToIndex(lang.getLinkageID(), ast, codeReader, ctx, pm); } } catch (CoreException e) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 03c11be0d0c..c24e8d698af 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -89,6 +89,7 @@ import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacroReferenceName; import org.eclipse.cdt.internal.core.pdom.dom.PDOMName; import org.eclipse.cdt.internal.core.pdom.dom.PDOMNamedNode; import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.cdt.internal.core.pdom.tag.PDOMTagIndex; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; @@ -230,10 +231,12 @@ public class PDOM extends PlatformObject implements IPDOM { * 138.0 - Constexpr functions, bug 395238. * 139.0 - More efficient and robust storage of types and template arguments, bug 395243. * 140.0 - Enumerators with dependent values, bug 389009. + * 140.1 - Mechanism for tagging nodes with extended data, bug TODO */ + private static final int MIN_SUPPORTED_VERSION= version(140, 0); private static final int MAX_SUPPORTED_VERSION= version(140, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(140, 0); + private static final int DEFAULT_VERSION = version(140, 1); private static int version(int major, int minor) { return (major << 16) + minor; @@ -269,7 +272,8 @@ public class PDOM extends PlatformObject implements IPDOM { public static final int INDEX_OF_DEFECTIVE_FILES = Database.DATA_AREA + 8; public static final int INDEX_OF_FILES_WITH_UNRESOLVED_INCLUDES = Database.DATA_AREA + 12; public static final int PROPERTIES = Database.DATA_AREA + 16; - public static final int END= Database.DATA_AREA + 20; + public static final int TAG_INDEX = Database.DATA_AREA + 20; + public static final int END= Database.DATA_AREA + 24; static { assert END <= Database.CHUNK_SIZE; } @@ -331,6 +335,7 @@ public class PDOM extends PlatformObject implements IPDOM { // Local caches protected Database db; private BTree fileIndex; + private PDOMTagIndex tagIndex; private BTree indexOfDefectiveFiles; private BTree indexOfFiledWithUnresolvedIncludes; private final Map fLinkageIDCache = new HashMap(); @@ -459,6 +464,15 @@ public class PDOM extends PlatformObject implements IPDOM { return fileIndex; } + public PDOMTagIndex getTagIndex() throws CoreException { + if (tagIndex == null) + { + // tag index can only be stored in database versions 139.1 or greater + tagIndex = new PDOMTagIndex( db.getVersion() >= version( 139, 1 ) ? db : null, TAG_INDEX ); + } + return tagIndex; + } + /** * Returns the index of files that were read with I/O errors. */ @@ -1357,6 +1371,7 @@ public class PDOM extends PlatformObject implements IPDOM { private void clearCaches() { fileIndex= null; + tagIndex = null; indexOfDefectiveFiles= null; indexOfFiledWithUnresolvedIncludes= null; fLinkageIDCache.clear(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java new file mode 100644 index 00000000000..976278d06e7 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/PDOMStringSet.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.db; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +/** + * A container for storing a set of strings in the Database. The container allows only one + * instance of each string to be stored. + *

+ * This implementation should only be used when the set is expected to be small. It uses a + * singly linked list for storing strings in Database. Which means that a linear lookup is needed + * to find strings in the list. An in-memory, lazily-loaded, cache is provided so the list will + * only be fully retrieved once in the lifetime of this instance. A BTree will be more efficient + * for larger sets. + */ +public class PDOMStringSet +{ + private final Database db; + + private long ptr; + private long head; + private long loaded; + + private Map lazyCache; + + public PDOMStringSet( Database db, long ptr ) throws CoreException + { + this.db = db; + this.ptr = ptr; + + head = 0; + loaded = 0; + } + + public void clearCaches() + { + head = 0; + loaded = 0; + + if( lazyCache != null ) + lazyCache = null; + } + + private long getHead() throws CoreException + { + if( head == 0 ) + head = db.getRecPtr( ptr ); + return head; + } + + // A simple enum describing the type of the information that is stored in the Database. Each + // enumerator represents a single field in the persistent structure and is able to answer its + // offset in that structure. + private static enum NodeType + { + Next, + Item, + _last; + + // NOTE: All fields are pointers, if that changes then these initializations will need + // to be updated. + public final long offset = ordinal() * Database.PTR_SIZE; + public static final int sizeof = (int)_last.offset; + + /** Return the value of the pointer stored in this field in the given instance. */ + public long get( Database db, long instance ) throws CoreException + { + return db.getRecPtr( instance + offset ); + } + + /** Store the given pointer into this field in the given instance. */ + public void put( Database db, long instance, long value ) throws CoreException + { + db.putRecPtr( instance + offset, value ); + } + } + + /** + * Adds the given string to the receiving set. May cause the entire list to be loaded from the + * Database while testing for uniqueness. Returns the record of the string that was inserted into + * the list. + */ + public long add( String str ) throws CoreException + { + long record = find( str ); + if( record != 0 ) + return record; + + IString string = db.newString( str ); + record = string.getRecord(); + + long new_node = db.malloc( NodeType.sizeof ); + NodeType.Next.put( db, new_node, getHead() ); + NodeType.Item.put( db, new_node, record ); + + if( lazyCache == null ) + lazyCache = new HashMap(); + lazyCache.put( str, record ); + + // If the Database has already been partially searched, then the loaded pointer will be after the + // head. Since we've already put this new record into the lazy cache, there is no reason to try to + // load it again. We put the new node at the start of the list so that it will be before the loaded + // pointer. + head = new_node; + if( loaded == 0 ) + loaded = new_node; + db.putRecPtr( ptr, new_node ); + return record; + } + + /** + * Search for the given string in the receiver. This could cause the entire list to be loaded from + * the Database. The results are cached, so the list will only be loaded one time during the lifetime + * of this instance. Returns the record of the String. + */ + public long find( String str ) throws CoreException + { + if( lazyCache != null ) + { + Long l = lazyCache.get( str ); + if( l != null ) + return l.longValue(); + } + + // if there is nothing in the Database, then there is nothing to load + if( getHead() == 0 ) + return 0; + + // otherwise prepare the cache for the data that is about to be loaded + if( lazyCache == null ) + lazyCache = new HashMap(); + + // if nothing has been loaded, then start loading with the head node, otherwise continue + // loading from whatever is after the last loaded node + long curr = loaded == 0 ? getHead() : NodeType.Next.get( db, loaded ); + while( curr != 0 ) + { + long next = NodeType.Next.get( db, curr ); + long item = NodeType.Item.get( db, curr ); + + IString string = db.getString( item ); + + // put the value into the cache + lazyCache.put( string.getString(), Long.valueOf( item ) ); + + // return immediately if this is the target + if( string.compare( str, true ) == 0 ) + return item; + + // otherwise keep looking + loaded = curr; + curr = next; + } + + return 0; + } + + /** + * Return a pointer to the record of the String that was removed. + */ + public long remove( String str ) throws CoreException + { + if( lazyCache != null ) + lazyCache.remove( str ); + + long prev = 0; + long curr = getHead(); + while( curr != 0 ) + { + long next = NodeType.Next.get( db, curr ); + long item = NodeType.Item.get( db, curr ); + + IString string = db.getString( item ); + + if( string.compare( str, true ) == 0 ) + { + if( head != curr ) + NodeType.Next.put( db, prev, next ); + else + { + db.putRecPtr( ptr, next ); + head = next; + } + + db.free( curr ); + return item; + } + + prev = curr; + curr = next; + } + + return 0; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java index 769d7a0071f..233bda56d5a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMBinding.java @@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; @@ -36,6 +37,7 @@ import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.db.Database; import org.eclipse.cdt.internal.core.pdom.db.IString; +import org.eclipse.cdt.internal.core.pdom.tag.PDOMTaggable; import org.eclipse.core.runtime.CoreException; /** @@ -67,6 +69,14 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding if (adapter.isAssignableFrom(PDOMBinding.class)) return this; + // Any PDOMBinding can have a persistent tag. These tags should be deleted when the PDOMBinding + // is deleted. However, PDOMBinding's don't get deleted, so there is no way to trigger deleting + // of the tags. If the implementation is changed so that PDOMBindings do get deleted, then call: + // PDOMTagIndex.setTags( getPDOM(), pdomBinding.record, Collections.emptyList() ); + // to clear out all tags for the binding. + if (adapter == ITagReader.class) + return new PDOMTaggable( getPDOM(), getRecord() ); + return null; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java index dd7be434ab3..77608c1b493 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/c/PDOMCLinkage.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.index.IIndexBinding; +import org.eclipse.cdt.internal.core.dom.ast.tag.TagManager; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; @@ -97,6 +98,11 @@ class PDOMCLinkage extends PDOMLinkage implements IIndexCBindingConstants { if (pdomBinding != null) { getPDOM().putCachedResult(inputBinding, pdomBinding); } + + // Synchronize the tags associated with the persistent binding to match the set that is + // associated with the input binding. + TagManager.getInstance().syncTags( pdomBinding, inputBinding ); + return pdomBinding; } @@ -104,7 +110,13 @@ class PDOMCLinkage extends PDOMLinkage implements IIndexCBindingConstants { } if (shouldUpdate(pdomBinding, fromName)) { - pdomBinding.update(this, fromName.getBinding()); + IBinding fromBinding = fromName.getBinding(); + + pdomBinding.update(this, fromBinding); + + // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but + // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation. + TagManager.getInstance().syncTags( pdomBinding, fromBinding ); } return pdomBinding; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java index 656dfb02abd..3d85ab48e7f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java @@ -75,6 +75,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.Util; +import org.eclipse.cdt.internal.core.dom.ast.tag.TagManager; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; @@ -358,6 +359,10 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { if (inputBinding instanceof CPPClosureType) { addImplicitMethods(pdomBinding, (ICPPClassType) binding, fromName); } + + // Synchronize the tags associated with the persistent binding to match the set that is + // associated with the input binding. + TagManager.getInstance().syncTags( pdomBinding, inputBinding ); } } catch (DOMException e) { throw new CoreException(Util.createStatus(e)); @@ -367,8 +372,15 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { } if (shouldUpdate(pdomBinding, fromName)) { - pdomBinding.update(this, fromName.getBinding()); + IBinding fromBinding = fromName.getBinding(); + + pdomBinding.update(this, fromBinding); + + // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but + // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation. + TagManager.getInstance().syncTags( pdomBinding, fromBinding ); } + return pdomBinding; } @@ -408,7 +420,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { // template parameters are created directly by their owners. if (binding instanceof ICPPTemplateParameter) return null; - if (binding instanceof ICPPUnknownBinding) + if (binding instanceof ICPPUnknownBinding) return null; if (binding instanceof ICPPSpecialization) { @@ -561,6 +573,10 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { } else if (!getPDOM().hasLastingDefinition(pdomBinding)) { pdomBinding.update(this, method); old.remove(pdomBinding); + + // Update the tags based on the tags from the new binding. This was in PDOMBinding.update, but + // I found that not all subclasses (e.g., PDOMCPPFunction) call the parent implementation. + TagManager.getInstance().syncTags( pdomBinding, method ); } } } @@ -691,7 +707,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { if (result != null) { return result; } - + // Assign names to anonymous types. IBinding binding= PDOMASTAdapter.getAdapterForAnonymousASTBinding(inputBinding); if (binding == null) { @@ -1111,7 +1127,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { return CPPPointerToMemberType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE: return TypeOfDependentExpression.unmarshal(firstByte, buffer); - case ITypeMarshalBuffer.UNKNOWN_MEMBER: + case ITypeMarshalBuffer.UNKNOWN_MEMBER: IBinding binding= CPPUnknownMember.unmarshal(getPDOM(), firstByte, buffer); if (binding instanceof IType) return (IType) binding; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java new file mode 100644 index 00000000000..1ea29d1fff7 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/BTreeIterable.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.tag; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.internal.core.pdom.db.BTree; +import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; +import org.eclipse.core.runtime.CoreException; + +public class BTreeIterable implements Iterable +{ + public static interface Descriptor + { + public int compare( long record ) throws CoreException; + public T create( long record ); + } + + private final BTree btree; + private final Descriptor descriptor; + + public BTreeIterable( BTree btree, Descriptor descriptor ) + { + this.btree = btree; + this.descriptor = descriptor; + } + + @Override + public Iterator iterator() + { + Visitor v = new Visitor(); + try { btree.accept( v ); } + catch( CoreException e ) { CCorePlugin.log( e ); return Collections.emptyList().iterator(); } + return new BTreeIterator( v.records ); + } + + private class Visitor implements IBTreeVisitor + { + public final List records = new LinkedList(); + + @Override + public int compare( long record ) throws CoreException + { + return BTreeIterable.this.descriptor.compare( record ); + } + + @Override + public boolean visit( long record ) throws CoreException + { + records.add( Long.valueOf( record ) ); + return true; + } + } + + private class BTreeIterator implements Iterator + { + private final Iterator records; + + public BTreeIterator( Iterable records ) + { + this.records = records.iterator(); + } + + @Override public void remove() { } + @Override public boolean hasNext() { return records.hasNext(); } + @Override public T next() { return BTreeIterable.this.descriptor.create( records.next() ); } + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java new file mode 100644 index 00000000000..ed7bfe63347 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTag.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.tag; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator; +import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; +import org.eclipse.core.runtime.CoreException; + +public class PDOMTag implements IWritableTag +{ + private final Database db; + private final long record; + + private String taggerId; + private int dataLen = -1; + + private static enum Fields + { + Node, + TaggerId, + DataLen, + Data; + + public final long offset = ordinal() * Database.PTR_SIZE; + public static int sizeof( int datalen ) { return (int)Data.offset + datalen; } + + public long getRecPtr( Database db, long instance, long data_offset ) throws CoreException + { + return db.getRecPtr( instance + offset + data_offset ); + } + + public void putRecPtr( Database db, long instance, long data_offset, long value ) throws CoreException + { + db.putRecPtr( instance + offset + data_offset, value ); + } + + public void put( Database db, long instance, long data_offset, byte value ) throws CoreException + { + db.putByte( instance + offset + data_offset, value ); + } + + public void put( Database db, long instance, byte[] data, long data_offset, int len ) throws CoreException + { + db.putBytes( instance + offset + data_offset, data, len ); + } + + public byte getByte( Database db, long instance, long data_offset ) throws CoreException + { + return db.getByte( instance + offset + data_offset ); + } + + public byte[] getBytes( Database db, long instance, long data_offset, int len ) throws CoreException + { + byte[] data = new byte[len]; + db.getBytes( instance + offset + data_offset, data ); + return data; + } + + public void put( Database db, long instance, long data_offset, int value ) throws CoreException + { + db.putInt( instance + offset + data_offset, value ); + } + + public int getInt( Database db, long instance, long data_offset ) throws CoreException + { + return db.getInt( instance + offset + data_offset ); + } + } + + public PDOMTag( Database db, long record ) + { + this.db = db; + this.record = record; + } + + public PDOMTag( Database db, int dataLen ) throws CoreException + { + this.db = db; + this.record = db.malloc( Fields.sizeof( dataLen ) ); + this.dataLen = dataLen; + Fields.DataLen.put( db, record, 0, dataLen ); + } + + public long getNode() throws CoreException + { + return Fields.Node.getRecPtr( db, record, 0 ); + } + + @Override + public String getTaggerId() + { + if( taggerId == null ) + try + { + long taggerIdRecord = Fields.TaggerId.getRecPtr( db, record, 0 ); + taggerId = taggerIdRecord == 0L ? new String() : db.getString( taggerIdRecord ).getString(); + } + catch( CoreException e ) + { + CCorePlugin.log( e ); + } + + return taggerId; + } + + @Override + public int getDataLen() + { + if( dataLen < 0 ) + try { dataLen = Fields.DataLen.getInt( db, record, 0 ); } + catch( CoreException e ) { CCorePlugin.log( e ); return 0; } + + return dataLen; + } + + public long getRecord() { return record; } + + /** + * Create and return a new PDOMTag that has the same node/taggerId as the receiver but with the + * specified data. Return null on failure. + */ + public PDOMTag cloneWith( byte[] data ) throws CoreException + { + PDOMTag partialTag = null; + try + { + long existing_node = Fields.Node.getRecPtr( db, record, 0 ); + long existing_id = Fields.TaggerId.getRecPtr( db, record, 0 ); + + partialTag = new PDOMTag( db, data.length ); + Fields.Node.putRecPtr( db, partialTag.record, 0, existing_node ); + Fields.TaggerId.putRecPtr( db, partialTag.record, 0, existing_id ); + if( partialTag.putBytes( 0, data, data.length ) ) + { + PDOMTag tag = partialTag; + partialTag = null; + return tag; + } + } + finally + { + if( partialTag != null ) + partialTag.delete(); + } + + return null; + } + + public void delete() + { + if( db != null + && record != 0 ) + try { db.free( record ); } + catch( CoreException e ) { CCorePlugin.log( e ); } + } + + public static class BTreeComparator implements IBTreeComparator + { + private final Database db; + public BTreeComparator( Database db ) { this.db = db; } + + @Override + public int compare(long record1, long record2) throws CoreException + { + if( record1 == record2 ) + return 0; + + long node1 = Fields.Node.getRecPtr( db, record1, 0 ); + long node2 = Fields.Node.getRecPtr( db, record2, 0 ); + if( node1 < node2 ) + return -1; + if( node1 > node2 ) + return 1; + + long tagger1 = Fields.TaggerId.getRecPtr( db, record1, 0 ); + long tagger2 = Fields.TaggerId.getRecPtr( db, record2, 0 ); + if( tagger1 < tagger2 ) + return -1; + if( tagger1 > tagger2 ) + return 1; + + return 0; + } + } + + public static class BTreeVisitor implements IBTreeVisitor + { + private final Database db; + private final long node2; + private final long tagger2; + + public boolean hasResult = false; + public long tagRecord = 0; + + public BTreeVisitor( Database db, long node2, long tagger2 ) + { + this.db = db; + this.node2 = node2; + this.tagger2 = tagger2; + } + + @Override + public int compare(long record1) throws CoreException { + long node1 = Fields.Node.getRecPtr( db, record1, 0 ); + if( node1 < node2 ) + return -1; + if( node1 > node2 ) + return 1; + + long tagger1 = Fields.TaggerId.getRecPtr( db, record1, 0 ); + if( tagger1 < tagger2 ) + return -1; + if( tagger1 > tagger2 ) + return 1; + + return 0; + } + + @Override + public boolean visit(long record) throws CoreException { + tagRecord = record; + hasResult = true; + return false; + } + } + + public void setNode( long node ) throws CoreException + { + Fields.Node.putRecPtr( db, record, 0, node ); + } + + public void setTaggerId( long idRecord ) throws CoreException + { + Fields.TaggerId.putRecPtr( db, record, 0, idRecord ); + } + + private boolean isInBounds( int offset, int len ) + { + int data_len = getDataLen(); + return offset >= 0 + && offset < data_len + && ( offset + len ) <= data_len; + } + + @Override + public boolean putByte( int offset, byte data ) + { + if( ! isInBounds( offset, 1 ) ) + return false; + + try { Fields.Data.put( db, record, offset, data ); return true; } + catch( CoreException e ) { CCorePlugin.log( e ); return false; } + } + + @Override + public boolean putBytes( int offset, byte[] data, int len ) + { + boolean fullWrite = len < 0; + if( fullWrite ) + len = data.length; + if( ! isInBounds( offset, len ) ) + return false; + + try + { + Fields.Data.put( db, record, data, offset, len ); + + // if the new buffer replaces all of the existing one, then modify the receiver's stored length + int currLen = getDataLen(); + if( fullWrite + && offset == 0 + && currLen > len ) + { + Fields.DataLen.put( db, record, 0, len ); + dataLen = len; + } + + return true; + } + catch( CoreException e ) { CCorePlugin.log( e ); return false; } + } + + @Override + public int getByte( int offset ) + { + if( ! isInBounds( offset, 1 ) ) + return Fail; + + try { return Fields.Data.getByte( db, record, offset ); } + catch( CoreException e ) { CCorePlugin.log( e ); return Fail; } + } + + @Override + public byte[] getBytes( int offset, int len ) + { + len = len >= 0 ? len : getDataLen() - offset; + if( ! isInBounds( offset, len ) ) + return null; + + try { return Fields.Data.getBytes( db, record, offset, len ); } + catch( CoreException e ) { CCorePlugin.log( e ); return null; } + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java new file mode 100644 index 00000000000..8cd0c86c9f9 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagIndex.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.tag; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.internal.core.pdom.PDOM; +import org.eclipse.cdt.internal.core.pdom.db.BTree; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.PDOMStringSet; +import org.eclipse.core.runtime.CoreException; + +/** + * Not thread-safe. + */ +public class PDOMTagIndex +{ + private final Database db; + private final long ptr; + private long rootRecord; + + private static enum Fields + { + TaggerIds, + Tags, + _last; + + public final long offset = ordinal() * Database.PTR_SIZE; + public static int sizeof = _last.ordinal() * Database.PTR_SIZE; + } + + private PDOMStringSet taggerIds; + private BTree tags; + + public PDOMTagIndex( Database db, long ptr ) throws CoreException + { + this.db = db; + this.ptr = ptr; + this.rootRecord = 0; + } + + private long getFieldAddress( Fields field ) throws CoreException + { + if( rootRecord == 0 ) + rootRecord = db.getRecPtr( ptr ); + + if( rootRecord == 0 ) + { + rootRecord = db.malloc( Fields.sizeof ); + db.putRecPtr( ptr, rootRecord ); + } + + return rootRecord + field.offset; + } + + private PDOMStringSet getTaggerIds() throws CoreException + { + if( taggerIds == null ) + taggerIds = new PDOMStringSet( db, getFieldAddress( Fields.TaggerIds ) ); + return taggerIds; + } + + private BTree getTagsBTree() throws CoreException + { + if( tags == null ) + tags = new BTree( db, getFieldAddress( Fields.Tags ), new PDOMTag.BTreeComparator( db ) ); + return tags; + } + + /** + * Return the record storing the specified tagger id. Create a new record if needed. + */ + private long getIdRecord( String taggerId, boolean createIfNeeded ) + { + assert taggerId != null; + assert ! taggerId.isEmpty(); + + if( db == null + || taggerId == null + || taggerId.isEmpty() + || ( taggerIds == null && ! createIfNeeded ) ) + return 0L; + + try + { + long record = getTaggerIds().find( taggerId ); + if( record == 0 + && createIfNeeded ) + record = getTaggerIds().add( taggerId ); + return record; + } + catch( CoreException e ) + { + CCorePlugin.log( e ); + } + + return 0L; + } + + private IWritableTag createTag( long record, String id, int len ) + { + if( db == null ) + return null; + + long idRecord = getIdRecord( id, true ); + if( idRecord == 0L ) + return null; + + try + { + PDOMTag tag = new PDOMTag( db, len ); + tag.setNode( record ); + tag.setTaggerId( idRecord ); + + // return the tag if it was properly inserted + long inserted = getTagsBTree().insert( tag.getRecord() ); + if( inserted == tag.getRecord() ) + return tag; + + // TODO check that the existing record has the same length + + // otherwise destroy this provisional one and return the tag that was actually inserted + // TODO figure out what this case means + tag.delete(); + return inserted == 0 ? null : new PDOMTag( db, inserted ); + } + catch( CoreException e ) + { + CCorePlugin.log( e ); + } + + return null; + } + + private ITag getTag( long record, String id ) + { + if( db == null ) + return null; + + long idRecord = getIdRecord( id, false ); + if( idRecord == 0L ) + return null; + + PDOMTag.BTreeVisitor v = new PDOMTag.BTreeVisitor( db, record, idRecord ); + try { getTagsBTree().accept( v ); } + catch( CoreException e ) { CCorePlugin.log( e ); } + + return v.hasResult ? new PDOMTag( db, v.tagRecord ) : null; + } + + private Iterable getTags( long binding_record ) + { + BTree btree = null; + try { btree = getTagsBTree(); } + catch( CoreException e ) { CCorePlugin.log( e ); return Collections.emptyList(); } + + final Long bindingRecord = Long.valueOf( binding_record ); + return + new BTreeIterable( + btree, + new BTreeIterable.Descriptor() + { + @Override public ITag create( long record ) { return new PDOMTag( db, record ); } + @Override + public int compare( long test_record ) throws CoreException + { + long test_node = new PDOMTag( db, test_record ).getNode(); + + // -1 if record < key, 0 if record == key, 1 if record > key + return Long.valueOf( test_node ).compareTo( bindingRecord ); + } + } ); + } + + private boolean setTags( long binding_record, Iterable tags ) + { + // There could be several tags for the given record in the database, one for each taggerId. We need + // to delete all of those tags and replace them with given list. The incoming tags are first put + // into a map, indexed by their taggerId. Then we examine the btree of tags to find all tags for this + // record. In each case we decide whether to delete or update the tag. Tags of the same size can be + // updated in place, otherwise the tag needs to be deleted and recreated. + + final Map newTags = new HashMap(); + for( ITag tag : tags ) + { + ITag dupTag = newTags.put( tag.getTaggerId(), tag ); + if( dupTag != null ) + CCorePlugin.log( "Duplicate incoming tag for record " + binding_record + " from taggerId " + tag.getTaggerId() ); //$NON-NLS-1$ //$NON-NLS-2$ + } + + BTree btree = null; + try { btree = getTagsBTree(); } + catch( CoreException e ) { CCorePlugin.log( e ); return false; } + + PDOMTagSynchronizer sync = new PDOMTagSynchronizer( db, Long.valueOf( binding_record ), newTags ); + + // visit the full tree, then return true on success and false on failure + try { btree.accept( sync ); } + catch( CoreException e ) { CCorePlugin.log( e ); return false; } + + // Complete the synchronization (delete/insert the records that could not be modified in-place). This + // will only have something to do when a tag has changed length, which should be a rare. + sync.synchronize( btree ); + + // insert any new tags that are left in the incoming list + for( ITag newTag : newTags.values() ) + { + IWritableTag pdomTag = createTag( binding_record, newTag.getTaggerId(), newTag.getDataLen() ); + pdomTag.putBytes( 0, newTag.getBytes( 0, -1 ), -1 ); + } + + return true; + } + + private static PDOMTagIndex getTagIndex( PDOM pdom ) + { + if( pdom == null ) + return null; + + try + { + PDOMTagIndex index = pdom.getTagIndex(); + return index.db == null ? null : index; + } + catch( CoreException e ) { CCorePlugin.log(e); } + return null; + } + + // common implementations + public static IWritableTag createTag( PDOM pdom, long record, String id, int len ) + { + PDOMTagIndex index = getTagIndex( pdom ); + if( index == null ) + return null; + + return index.createTag( record, id, len ); + } + + public static ITag getTag( PDOM pdom, long record, String id ) + { + PDOMTagIndex index = getTagIndex( pdom ); + if( index == null ) + return null; + + return index.getTag( record, id ); + } + + public static Iterable getTags( PDOM pdom, long record ) + { + PDOMTagIndex index = getTagIndex( pdom ); + if( index == null ) + return Collections.emptyList(); + + return index.getTags( record ); + } + + public static boolean setTags( PDOM pdom, long record, Iterable tags ) + { + if( record == 0 ) + return true; + + PDOMTagIndex index = getTagIndex( pdom ); + if( index == null ) + return false; + + return index.setTags( record, tags ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java new file mode 100644 index 00000000000..aca9c277272 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTagSynchronizer.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.tag; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.internal.core.pdom.db.BTree; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; +import org.eclipse.core.runtime.CoreException; + +public class PDOMTagSynchronizer implements IBTreeVisitor +{ + private final Database db; + private final Long searchRecord; + private final Map newTags; + + private final List toRemove = new LinkedList(); + private final List toInsert = new LinkedList(); + + public PDOMTagSynchronizer( Database db, Long searchRecord, Map newTags ) + { + this.db = db; + this.searchRecord = searchRecord; + this.newTags = newTags; + } + + /** + * Complete the synchronization by deleting and inserting all required records. Return + * true if successful and false otherwise. + */ + public boolean synchronize( BTree tree ) + { + for( Long rm : toRemove ) + try + { + long record = rm.longValue(); + tree.delete( record ); + db.free( record ); + } + catch( CoreException e ) + { + CCorePlugin.log( e ); + } + toRemove.clear(); + + for( Long insert : toInsert ) + try { tree.insert( insert.longValue() ); } + catch( CoreException e ) + { + CCorePlugin.log( e ); + try { db.free( insert.longValue() ); } + catch( CoreException e1 ) { CCorePlugin.log( e1 ); } + } + toInsert.clear(); + + return true; + } + + @Override + public int compare( long test_record ) throws CoreException + { + // TODO this is the same as BTreeIterable.Descriptor.compare + + long test_node = new PDOMTag( db, test_record ).getNode(); + + // -1 if record < key, 0 if record == key, 1 if record > key + return Long.valueOf( test_node ).compareTo( searchRecord ); + } + + @Override + public boolean visit( long existing_record ) throws CoreException + { + PDOMTag existingTag = new PDOMTag( db, existing_record ); + String taggerId = existingTag.getTaggerId(); + + ITag newTag = newTags.remove( taggerId ); + if( newTag == null ) + toRemove.add( Long.valueOf( existing_record ) ); + else if( newTag.getDataLen() > existingTag.getDataLen() ) + { + toRemove.add( Long.valueOf( existing_record ) ); + + PDOMTag pdomTag = existingTag.cloneWith( newTag.getBytes( 0, -1 ) ); + if( pdomTag != null ) + toInsert.add( Long.valueOf( pdomTag.getRecord() ) ); + } + else if( ! existingTag.putBytes( 0, newTag.getBytes( 0, -1 ), -1 ) ) + CCorePlugin.log( "Unable to modify data of tag record " + existing_record + " from taggerId " + taggerId ); //$NON-NLS-1$ //$NON-NLS-2$ + + // try to visit the full tree + return true; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java new file mode 100644 index 00000000000..e7a04c839ed --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/tag/PDOMTaggable.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.internal.core.pdom.tag; + +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.internal.core.pdom.PDOM; + +public class PDOMTaggable implements ITagReader, ITagWriter +{ + private final PDOM pdom; + private final long record; + + public PDOMTaggable( PDOM pdom, long record ) + { + this.pdom = pdom; + this.record = record; + } + + @Override + public IWritableTag createTag( String id, int len ) + { + return PDOMTagIndex.createTag( pdom, record, id, len ); + } + + @Override + public ITag getTag( String id ) + { + return PDOMTagIndex.getTag( pdom, record, id ); + } + + @Override + public Iterable getTags() + { + return PDOMTagIndex.getTags( pdom, record ); + } + + @Override + public boolean setTags( Iterable tags ) + { + return PDOMTagIndex.setTags( pdom, record, tags ); + } +} diff --git a/core/org.eclipse.cdt.core/plugin.properties b/core/org.eclipse.cdt.core/plugin.properties index 46e1547c2f1..287ee250127 100644 --- a/core/org.eclipse.cdt.core/plugin.properties +++ b/core/org.eclipse.cdt.core/plugin.properties @@ -121,6 +121,7 @@ CConfigurationDataProvider.name = CConfigurationData provider projectConverter.name = project converter CIndex.name = CIndex externalSettingsProvider.name = External Settings provider +tagger.name = Parser Node Tagger Extension Point GeneratePDOMApplication.name = GeneratePDOM defaultProvider.name = Default Provider templatesExtensionPoint.name = Templates Extension point diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index bb1125caabd..4b2e257ed6a 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -42,6 +42,7 @@ + diff --git a/core/org.eclipse.cdt.core/schema/tagger.exsd b/core/org.eclipse.cdt.core/schema/tagger.exsd new file mode 100644 index 00000000000..98d37683785 --- /dev/null +++ b/core/org.eclipse.cdt.core/schema/tagger.exsd @@ -0,0 +1,139 @@ + + + + + + + + + This extension point allows extensions to contribute to the parsed nodes. When PDOM nodes are tagged, the content of the tag is stored in to the Database. The information for other nodes, e.g., the AST, is stored in memory. + + + + + + + + + + + + + + + + + + + a fully qualified identifier of the target extension point + + + + + + + an optional identifier of the extension instance + + + + + + + an optional name of the extension instance + + + + + + + + + + + + + + + + + + + + + + + + + + + A unique identifier for this tagger's contributions. + +The local id will be appended to the contributing plugin's id (separated with a dot '.') to form the globally unique identifier for this tagger. This id is used to uniquely associate the tag with this plugin. + + + + + + + + + + + + 8.2 + + + + + + + + + The following is an example of a Tagger contribution: +<p> +<pre> +<extension + point="org.eclipse.cdt.core.tagger" + id="example" + name="Example Tagger Extension"> + <bindingTagger + local-id="my-tagger" + class="com.example.internal.ExampleTagger"> + <enablement> + <with variable="projectNatures"> + <iterate operator="or"> + <equals value="com.example.my-nature"/> + </iterate> + </with> + </enablement> + </bindingTagger> +</extension> +</pre> +</p> + + + + + + + + + The contributed class must implement <code>org.eclipse.cdt.core.dom.ast.tag.IBindingTagger</code> + + + + + + + + + + Copyright (c) 2013 QNX Software Systems and others. +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +which accompanies this distribution, and is available at +http://www.eclipse.org/legal/epl-v10.html + + + + diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index 22a22903a2e..b5fc7a7384f 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -26,6 +26,7 @@ import java.util.ResourceBundle; import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager; import org.eclipse.cdt.core.cdtvariables.IUserVarSupplier; import org.eclipse.cdt.core.dom.IPDOMManager; +import org.eclipse.cdt.core.dom.ast.tag.ITagService; import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport; @@ -50,6 +51,7 @@ import org.eclipse.cdt.internal.core.ICConsole; import org.eclipse.cdt.internal.core.PositionTrackerManager; import org.eclipse.cdt.internal.core.cdtvariables.CdtVariableManager; import org.eclipse.cdt.internal.core.cdtvariables.UserVarSupplier; +import org.eclipse.cdt.internal.core.dom.ast.tag.TagService; import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager; import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsScannerInfoProvider; import org.eclipse.cdt.internal.core.model.CModelManager; @@ -214,6 +216,8 @@ public class CCorePlugin extends Plugin { private PDOMManager pdomManager; + private ITagService tagService = new TagService(); + private CdtVarPathEntryVariableManager fPathEntryVariableManager; private final class NullConsole implements IConsole { @@ -713,6 +717,13 @@ public class CCorePlugin extends Plugin { return getDefault().pdomManager; } + /** + * @since 5.5 + */ + public static ITagService getTagService() { + return getDefault().tagService; + } + public IPathEntryVariableManager getPathEntryVariableManager() { return fPathEntryVariableManager; } From f1542b27c6218771330775dd0820e737fcd0514e Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Wed, 13 Feb 2013 00:57:09 -0500 Subject: [PATCH 07/11] Bug 399829 - Wrong context for name lookup in dependent expression Change-Id: Iab800a2264c56bdf01498c238b08a2948ca3cfc8 Reviewed-on: https://git.eclipse.org/r/10333 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../parser/tests/ast2/AST2TemplateTests.java | 67 +++++++++ .../cdt/internal/core/dom/parser/Value.java | 10 +- .../cpp/CPPASTArraySubscriptExpression.java | 2 +- .../parser/cpp/CPPASTBinaryExpression.java | 4 +- .../cpp/CPPASTBinaryTypeIdExpression.java | 2 +- .../dom/parser/cpp/CPPASTCastExpression.java | 2 +- .../CPPASTCompoundStatementExpression.java | 2 +- .../cpp/CPPASTConditionalExpression.java | 2 +- .../dom/parser/cpp/CPPASTExpressionList.java | 2 +- .../dom/parser/cpp/CPPASTFieldReference.java | 4 +- .../cpp/CPPASTFunctionCallExpression.java | 4 +- .../dom/parser/cpp/CPPASTInitializerList.java | 2 +- ...CPPASTSimpleTypeConstructorExpression.java | 5 +- .../parser/cpp/CPPASTTypeIdExpression.java | 2 +- .../CPPASTTypeIdInitializerExpression.java | 2 +- .../dom/parser/cpp/CPPASTUnaryExpression.java | 2 +- .../cpp/CPPTemplateNonTypeArgument.java | 2 +- .../core/dom/parser/cpp/ICPPEvaluation.java | 8 + .../cpp/semantics/CPPDependentEvaluation.java | 137 ++++++++++++++++++ .../parser/cpp/semantics/CPPEvaluation.java | 5 + .../parser/cpp/semantics/CPPSemantics.java | 76 ++++++---- .../parser/cpp/semantics/CPPTemplates.java | 20 +-- .../dom/parser/cpp/semantics/EvalBinary.java | 23 ++- .../cpp/semantics/EvalBinaryTypeId.java | 15 +- .../dom/parser/cpp/semantics/EvalBinding.java | 23 ++- .../dom/parser/cpp/semantics/EvalComma.java | 19 ++- .../parser/cpp/semantics/EvalCompound.java | 17 ++- .../parser/cpp/semantics/EvalConditional.java | 20 ++- .../cpp/semantics/EvalFunctionCall.java | 19 ++- .../parser/cpp/semantics/EvalFunctionSet.java | 16 +- .../core/dom/parser/cpp/semantics/EvalID.java | 39 +++-- .../parser/cpp/semantics/EvalInitList.java | 17 ++- .../cpp/semantics/EvalMemberAccess.java | 17 ++- .../dom/parser/cpp/semantics/EvalTypeId.java | 19 ++- .../dom/parser/cpp/semantics/EvalUnary.java | 20 ++- .../parser/cpp/semantics/EvalUnaryTypeID.java | 15 +- .../semantics/TemplateArgumentDeduction.java | 10 +- .../composite/cpp/CPPCompositesFactory.java | 66 +++++---- .../eclipse/cdt/internal/core/pdom/PDOM.java | 8 +- 39 files changed, 536 insertions(+), 189 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPDependentEvaluation.java 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 30a2844295d..5b5b5fefb4e 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 @@ -7202,6 +7202,73 @@ public class AST2TemplateTests extends AST2TestBase { // S::value>::type t; // } public void testVariadicTemplates_401024() throws Exception { + parseAndCheckBindings(); + } + + // struct S { + // void kind(); + // }; + // struct T {}; + // namespace N { + // S operator++(T); + // template + // struct impl { + // static T x; + // typedef decltype(++x) type; + // }; + // } + // void test() { + // N::impl::type operand; + // operand.kind(); // ERROR HERE: Method 'kind' could not be resolved + // } + public void testNameLookupInDependentExpression_399829a() throws Exception { + parseAndCheckBindings(); + } + + // struct S { + // void kind(); + // }; + // namespace N { + // struct tag {}; + // struct any { template any(T); }; + // tag operator++(any); + // tag operator,(tag,int); + // S check(tag); + // int check(int); + // template + // struct impl { + // static T& x; + // typedef decltype(N::check((++x,0))) type; + // }; + // } + // void test() { + // N::impl::type operand; + // operand.kind(); // ERROR HERE: Method 'kind' could not be resolved + // } + public void testNameLookupInDependentExpression_399829b() throws Exception { + parseAndCheckBindings(); + } + + // template int assertion_failed(void*); + // struct assert_ {}; + // assert_ arg; + // char operator==(assert_, assert_); + // template struct assert_relation {}; + // template + // struct concept { + // typedef decltype(assertion_failed((assert_relation*)0)) type; + // }; + // template struct S {}; + // template + // struct is_int + // { + // static const bool value = false; + // }; + // template + // S operator==(T, T*); + // template + // S<(is_int::value)> operator==(T, T); + public void testRegression_399829() throws Exception { parseAndCheckBindings(); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java index 8c074ef9932..5a5673d05f8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java @@ -56,6 +56,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; @@ -234,10 +235,11 @@ public class Value implements IValue { } /** - * Creates a value representing the given template parameter. + * Creates a value representing the given template parameter + * in the given template. */ - public static IValue create(ICPPTemplateNonTypeParameter tntp) { - EvalBinding eval = new EvalBinding(tntp, null); + public static IValue create(ICPPTemplateDefinition template, ICPPTemplateNonTypeParameter tntp) { + EvalBinding eval = new EvalBinding(tntp, null, template); return new Value(null, eval); } @@ -284,7 +286,7 @@ public class Value implements IValue { } ICPPEvaluation arg1 = value.getEvaluation(); EvalFixed arg2 = new EvalFixed(INT_TYPE, ValueCategory.PRVALUE, create(increment)); - return create(new EvalBinary(IASTBinaryExpression.op_plus, arg1, arg2)); + return create(new EvalBinary(IASTBinaryExpression.op_plus, arg1, arg2, arg1.getTemplateDefinition())); } private static Number applyUnaryTypeIdOperator(int operator, IType type, IASTNode point) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java index 111aee3c912..2068c5b6ef5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java @@ -197,7 +197,7 @@ public class CPPASTArraySubscriptExpression extends ASTNode private ICPPEvaluation computeEvaluation() { if (arrayExpression == null || subscriptExp == null) return EvalFixed.INCOMPLETE; - return new EvalBinary(EvalBinary.op_arrayAccess, arrayExpression.getEvaluation(), subscriptExp.getEvaluation()); + return new EvalBinary(EvalBinary.op_arrayAccess, arrayExpression.getEvaluation(), subscriptExp.getEvaluation(), this); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java index f8d836931c9..d53a27e9918 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java @@ -274,8 +274,8 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr private ICPPEvaluation computeEvaluation() { if (operand1 == null || operand2 == null) return EvalFixed.INCOMPLETE; - - return new EvalBinary(op, operand1.getEvaluation(), operand2.getEvaluation()); + + return new EvalBinary(op, operand1.getEvaluation(), operand2.getEvaluation(), this); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryTypeIdExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryTypeIdExpression.java index 916731241c1..8f66d94a242 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryTypeIdExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryTypeIdExpression.java @@ -128,7 +128,7 @@ public class CPPASTBinaryTypeIdExpression extends ASTNode implements ICPPASTExpr if (t1 == null || t2 == null) { fEvaluation= EvalFixed.INCOMPLETE; } else { - fEvaluation= new EvalBinaryTypeId(fOperator, t1, t2); + fEvaluation= new EvalBinaryTypeId(fOperator, t1, t2, this); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCastExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCastExpression.java index f1cf7b966f8..456e6263699 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCastExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCastExpression.java @@ -155,7 +155,7 @@ public class CPPASTCastExpression extends ASTNode implements ICPPASTCastExpressi if (type == null || type instanceof IProblemType) return EvalFixed.INCOMPLETE; - return new EvalTypeId(type, operand.getEvaluation()); + return new EvalTypeId(type, this, operand.getEvaluation()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCompoundStatementExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCompoundStatementExpression.java index 8d363e18898..623b8436c5c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCompoundStatementExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTCompoundStatementExpression.java @@ -42,7 +42,7 @@ public class CPPASTCompoundStatementExpression extends ASTNode implements IGNUAS if (statements.length > 0) { IASTStatement st = statements[statements.length - 1]; if (st instanceof IASTExpressionStatement) { - fEval= new EvalCompound(((ICPPASTExpression) ((IASTExpressionStatement) st).getExpression()).getEvaluation()); + fEval= new EvalCompound(((ICPPASTExpression) ((IASTExpressionStatement) st).getExpression()).getEvaluation(), this); } } if (fEval == null) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java index cbc866f92a6..4b2f09961b2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java @@ -170,7 +170,7 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio final ICPPEvaluation condEval = fCondition.getEvaluation(); final ICPPEvaluation posEval = fPositive == null ? null : fPositive.getEvaluation(); fEval= new EvalConditional(condEval, posEval, fNegative.getEvaluation(), - isThrowExpression(fPositive), isThrowExpression(fNegative)); + isThrowExpression(fPositive), isThrowExpression(fNegative), this); } } return fEval; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java index 17a3cde3860..9f14ca221b2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java @@ -178,7 +178,7 @@ public class CPPASTExpressionList extends ASTNode implements ICPPASTExpressionLi for (int i = 0; i < evals.length; i++) { evals[i]= ((ICPPASTExpression) exprs[i]).getEvaluation(); } - return new EvalComma(evals); + return new EvalComma(evals, this); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java index 827e8d992c7..d90230333e2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java @@ -260,7 +260,7 @@ public class CPPASTFieldReference extends ASTNode if (binding instanceof IProblemBinding || binding instanceof IType || binding instanceof ICPPConstructor) return EvalFixed.INCOMPLETE; - return new EvalMemberAccess(ownerType, ownerEval.getValueCategory(this), binding, isDeref); + return new EvalMemberAccess(ownerType, ownerEval.getValueCategory(this), binding, isDeref, this); } } @@ -283,7 +283,7 @@ public class CPPASTFieldReference extends ASTNode return EvalFixed.INCOMPLETE; } } - return new EvalID(ownerEval, qualifier, name.getSimpleID(), false, true, args); + return new EvalID(ownerEval, qualifier, name.getSimpleID(), false, true, args, this); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java index 555bba47128..269d24c139a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java @@ -303,7 +303,7 @@ public class CPPASTFunctionCallExpression extends ASTNode for (int i = 1; i < args.length; i++) { args[i]= ((ICPPASTInitializerClause) fArguments[i - 1]).getEvaluation(); } - return new EvalFunctionCall(args); + return new EvalFunctionCall(args, this); } private ICPPEvaluation checkForExplicitTypeConversion() { @@ -315,7 +315,7 @@ public class CPPASTFunctionCallExpression extends ASTNode for (int i = 0; i < args.length; i++) { args[i]= ((ICPPASTInitializerClause) fArguments[i]).getEvaluation(); } - return new EvalTypeId((IType) b, args); + return new EvalTypeId((IType) b, this, args); } } return null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInitializerList.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInitializerList.java index 1556865508f..08858266359 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInitializerList.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTInitializerList.java @@ -172,6 +172,6 @@ public class CPPASTInitializerList extends ASTNode implements ICPPASTInitializer for (int i = 0; i < evals.length; i++) { evals[i]= clauses[i].getEvaluation(); } - return new EvalInitList(evals); + return new EvalInitList(evals, this); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeConstructorExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeConstructorExpression.java index adb1ad1db1b..375b6a8a4a3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeConstructorExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeConstructorExpression.java @@ -100,9 +100,10 @@ public class CPPASTSimpleTypeConstructorExpression extends ASTNode implements for (int i = 0; i < a.length; i++) { args[i]= ((ICPPASTInitializerClause) a[i]).getEvaluation(); } - fEvaluation= new EvalTypeId(type, args); + fEvaluation= new EvalTypeId(type, this, args); } else if (fInitializer instanceof ICPPASTInitializerList) { - fEvaluation= new EvalTypeId(type, ((ICPPASTInitializerList) fInitializer).getEvaluation()); + fEvaluation= new EvalTypeId(type, this, + ((ICPPASTInitializerList) fInitializer).getEvaluation()); } else { fEvaluation= EvalFixed.INCOMPLETE; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdExpression.java index 5de9d648038..fee516ec4fd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdExpression.java @@ -103,7 +103,7 @@ public class CPPASTTypeIdExpression extends ASTNode implements ICPPASTTypeIdExpr if (type == null || type instanceof IProblemType) { fEvaluation= EvalFixed.INCOMPLETE; } else { - fEvaluation= new EvalUnaryTypeID(op, type); + fEvaluation= new EvalUnaryTypeID(op, type, this); } } return fEvaluation; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdInitializerExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdInitializerExpression.java index b4c7e7e523d..7330c3f81ec 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdInitializerExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTypeIdInitializerExpression.java @@ -65,7 +65,7 @@ public class CPPASTTypeIdInitializerExpression extends ASTTypeIdInitializerExpre if (type == null || type instanceof IProblemType) return EvalFixed.INCOMPLETE; - return new EvalTypeId(type, ((ICPPASTInitializerClause) initializer).getEvaluation()); + return new EvalTypeId(type, this, ((ICPPASTInitializerClause) initializer).getEvaluation()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java index 5176d296cf5..9a68aad31bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java @@ -204,7 +204,7 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres return EvalFixed.INCOMPLETE; } } - return new EvalUnary(fOperator, nestedEval, addressOfQualifiedNameBinding); + return new EvalUnary(fOperator, nestedEval, addressOfQualifiedNameBinding, this); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeArgument.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeArgument.java index 73129221962..d18ff891a0e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeArgument.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateNonTypeArgument.java @@ -94,7 +94,7 @@ public class CPPTemplateNonTypeArgument implements ICPPTemplateArgument { EvalFixed fixed = (EvalFixed) fEvaluation; evaluation = new EvalFixed(t, fixed.getValueCategory(), fixed.getValue()); } else { - evaluation = new EvalTypeId(t, fEvaluation); + evaluation = new EvalTypeId(t, fEvaluation.getTemplateDefinition(), fEvaluation); } return new CPPTemplateNonTypeArgument(evaluation, null); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java index 043325baa46..0a4fc340f15 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPEvaluation.java @@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -104,4 +105,11 @@ public interface ICPPEvaluation extends ISerializableEvaluation { * evaluations. */ boolean referencesTemplateParameter(); + + /** + * If the evaluation is dependent (or instantiated from a dependent + * evaluation), returns the template definition in which the + * evaluation occurs. Otherwise returns null. + */ + IBinding getTemplateDefinition(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPDependentEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPDependentEvaluation.java new file mode 100644 index 00000000000..650a36cc4bb --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPDependentEvaluation.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2013 Nathan Ridge. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Nathan Ridge + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.PlatformObject; + +/** + * Base class for evaluations that are dependent, or that have been instantiated + * from a dependent evaluation. These evaluations keep track of the template + * in which they are defined, so that certain name lookups can be performed + * starting from their point of definition. + */ +public abstract class CPPDependentEvaluation extends CPPEvaluation { + + private IBinding fTemplateDefinition; + private IScope fTemplateDefinitionScope; + + CPPDependentEvaluation(IBinding templateDefinition) { + fTemplateDefinition = templateDefinition; + } + + @Override + public IBinding getTemplateDefinition() { + if (fTemplateDefinition instanceof DeferredResolutionBinding) { + IBinding toResolve = fTemplateDefinition; + // While resolve() is called, set fTemplateDefinition to null to avoid + // infinite recursion in some cases where the resolution process ends + // up (indirectly) calling getTemplateDefinition() on this evaluation. + fTemplateDefinition = null; + fTemplateDefinition = ((DeferredResolutionBinding) toResolve).resolve(); + } + return fTemplateDefinition; + } + + protected IScope getTemplateDefinitionScope() { + if (fTemplateDefinitionScope == null) { + IBinding templateDefinition = getTemplateDefinition(); + if (templateDefinition != null) { + if (templateDefinition instanceof ICPPClassType) { + fTemplateDefinitionScope = ((ICPPClassType) templateDefinition).getCompositeScope(); + } + try { + fTemplateDefinitionScope = templateDefinition.getScope(); + } catch (DOMException e) { + } + } + } + return fTemplateDefinitionScope; + } + + /** + * If the given node is contained in some template declaration, + * return the binding for that template. Otherwise return null. + */ + protected static IBinding findEnclosingTemplate(IASTNode node) { + while (node != null) { + if (node instanceof ICPPASTTemplateDeclaration) { + ICPPASTTemplateDeclaration templateDecl = (ICPPASTTemplateDeclaration) node; + IASTName templateName = CPPTemplates.getTemplateName(templateDecl); + if (templateName == null) + return null; + return new DeferredResolutionBinding(templateName); + } + node = node.getParent(); + } + return null; + } + + protected void marshalTemplateDefinition(ITypeMarshalBuffer buffer) throws CoreException { + // Don't marshal the template definition when building a signature. + // While the template definition needs to be stored in the index, it does not + // need to be part of the signature, and trying to resolve it at the time a + // signature is built sometimes causes recursion (as the call to resolve() + // may end up needing the signature). + if (!(buffer instanceof SignatureBuilder)) + buffer.marshalBinding(getTemplateDefinition()); + } + + /** + * Used to defer the resolution of a template definition until it is needed, + * to avoid recursion. The only valid operation on this binding is resolve(). + */ + private static class DeferredResolutionBinding extends PlatformObject implements IBinding { + private final IASTName fName; + + public DeferredResolutionBinding(IASTName name) { + fName = name; + } + + public IBinding resolve() { + return fName.resolveBinding(); + } + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public char[] getNameCharArray() { + throw new UnsupportedOperationException(); + } + + @Override + public ILinkage getLinkage() { + throw new UnsupportedOperationException(); + } + + @Override + public IBinding getOwner() { + throw new UnsupportedOperationException(); + } + + @Override + public IScope getScope() throws DOMException { + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java index c68c28a7f23..99d2bf6d6c2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java @@ -27,6 +27,11 @@ public abstract class CPPEvaluation implements ICPPEvaluation { CPPEvaluation() { } + @Override + public IBinding getTemplateDefinition() { + return null; + } + @Override public char[] getSignature() { SignatureBuilder buf = new SignatureBuilder(); 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 70ca109fd0e..126a1dd02a6 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 @@ -391,7 +391,7 @@ public class CPPSemantics { if (CPPTemplates.areSameArguments(((ICPPClassTemplatePartialSpecialization) usedHere).getTemplateArguments(), dcl.getTemplateArguments())) binding= ((ICPPClassTemplatePartialSpecialization) usedHere).asDeferredInstance(); } else if (usedHere instanceof ICPPClassTemplate) { - if (CPPTemplates.areSameArguments(CPPTemplates.templateParametersAsArguments(((ICPPClassTemplate) usedHere).getTemplateParameters()), dcl.getTemplateArguments())) { + if (CPPTemplates.areSameArguments(CPPTemplates.templateParametersAsArguments((ICPPClassTemplate) usedHere), dcl.getTemplateArguments())) { binding= ((ICPPClassTemplate) usedHere).asDeferredInstance(); } } @@ -2503,9 +2503,10 @@ public class CPPSemantics { isCandidate= true; } else { // See 14.3-7 - final ICPPTemplateParameter[] tpars = ((ICPPFunctionTemplate) f).getTemplateParameters(); + ICPPFunctionTemplate funcTemp = (ICPPFunctionTemplate) f; + final ICPPTemplateParameter[] tpars = funcTemp.getTemplateParameters(); final CPPTemplateParameterMap map = new CPPTemplateParameterMap(tpars.length); - isCandidate= TemplateArgumentDeduction.addExplicitArguments(tpars, args, map, point); + isCandidate= TemplateArgumentDeduction.addExplicitArguments(funcTemp, tpars, args, map, point); } } else { isCandidate= args == null; @@ -2981,14 +2982,14 @@ public class CPPSemantics { return result; } - public static ICPPFunction findOverloadedBinaryOperator(IASTNode point, OverloadableOperator op, - ICPPEvaluation arg1, ICPPEvaluation arg2) { + public static ICPPFunction findOverloadedBinaryOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, + OverloadableOperator op, ICPPEvaluation arg1, ICPPEvaluation arg2) { if (op == null || arg1 == null || arg2 == null) return null; - IType op1type = getNestedType(arg1.getTypeOrFunctionSet(point), TDEF | REF | CVTYPE); + IType op1type = getNestedType(arg1.getTypeOrFunctionSet(pointOfInstantiation), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined( - getNestedType(arg2.getTypeOrFunctionSet(point), TDEF | REF | CVTYPE))) + getNestedType(arg2.getTypeOrFunctionSet(pointOfInstantiation), TDEF | REF | CVTYPE))) return null; final LookupMode lookupNonMember; @@ -2997,7 +2998,7 @@ public class CPPSemantics { } else { lookupNonMember= LookupMode.LIMITED_GLOBALS; } - return findOverloadedOperator(point, new ICPPEvaluation[] {arg1, arg2}, + return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, new ICPPEvaluation[] {arg1, arg2}, op1type, op, lookupNonMember); } @@ -3008,8 +3009,8 @@ public class CPPSemantics { return null; final IASTInitializerClause[] placement = expr.getPlacementArguments(); - final ICPPEvaluation arg1= new EvalUnary(IASTUnaryExpression.op_star, evaluation, null); - final ICPPEvaluation arg2= new EvalUnary(IASTUnaryExpression.op_sizeof, evaluation, null); + final ICPPEvaluation arg1= new EvalUnary(IASTUnaryExpression.op_star, evaluation, null, expr); + final ICPPEvaluation arg2= new EvalUnary(IASTUnaryExpression.op_sizeof, evaluation, null, expr); ICPPEvaluation[] args; if (placement == null) { @@ -3028,7 +3029,7 @@ public class CPPSemantics { } } IType type= getNestedType(arg1.getTypeOrFunctionSet(expr), TDEF | REF | CVTYPE); - return findOverloadedOperator(expr, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); + return findOverloadedOperator(expr, null, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); } public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression expr) { @@ -3041,7 +3042,7 @@ public class CPPSemantics { new EvalFixed(type, LVALUE, Value.UNKNOWN), ((ICPPASTExpression) expr.getOperand()).getEvaluation() }; - return findOverloadedOperator(expr, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); + return findOverloadedOperator(expr, null, args, type, op, LookupMode.GLOBALS_IF_NO_MEMBERS); } private static IType getTypeOfPointer(IType type) { @@ -3235,9 +3236,10 @@ public class CPPSemantics { /** * For simplicity returns an operator of form RT (T, T) rather than RT (boolean, T, T) */ - public static ICPPFunction findOverloadedConditionalOperator(IASTNode point, ICPPEvaluation positive, ICPPEvaluation negative) { + public static ICPPFunction findOverloadedConditionalOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, + ICPPEvaluation positive, ICPPEvaluation negative) { final ICPPEvaluation[] args = new ICPPEvaluation[] {positive, negative}; - return findOverloadedOperator(point, args, null, + return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, args, null, OverloadableOperator.CONDITIONAL_OPERATOR, LookupMode.NO_GLOBALS); } @@ -3245,27 +3247,29 @@ public class CPPSemantics { * Returns the operator,() function that would apply to the two given arguments. * The lookup type of the class where the operator,() might be found must also be provided. */ - public static ICPPFunction findOverloadedOperatorComma(IASTNode point, ICPPEvaluation arg1, ICPPEvaluation arg2) { - IType op1type = getNestedType(arg1.getTypeOrFunctionSet(point), TDEF | REF | CVTYPE); - IType op2type = getNestedType(arg2.getTypeOrFunctionSet(point), TDEF | REF | CVTYPE); + public static ICPPFunction findOverloadedOperatorComma(IASTNode pointOfInstantiation, IScope pointOfDefinition, + ICPPEvaluation arg1, ICPPEvaluation arg2) { + IType op1type = getNestedType(arg1.getTypeOrFunctionSet(pointOfInstantiation), TDEF | REF | CVTYPE); + IType op2type = getNestedType(arg2.getTypeOrFunctionSet(pointOfInstantiation), TDEF | REF | CVTYPE); if (!isUserDefined(op1type) && !isUserDefined(op2type)) return null; ICPPEvaluation[] args = { arg1 , arg2 }; - return findOverloadedOperator(point, args, op1type, OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS); + return findOverloadedOperator(pointOfInstantiation, pointOfDefinition, args, op1type, + OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS); } static enum LookupMode {NO_GLOBALS, GLOBALS_IF_NO_MEMBERS, LIMITED_GLOBALS, ALL_GLOBALS} - static ICPPFunction findOverloadedOperator(IASTNode point, ICPPEvaluation[] args, IType methodLookupType, - OverloadableOperator operator, LookupMode mode) { - while (point instanceof IASTName) - point= point.getParent(); + static ICPPFunction findOverloadedOperator(IASTNode pointOfInstantiation, IScope pointOfDefinition, + ICPPEvaluation[] args, IType methodLookupType, OverloadableOperator operator, LookupMode mode) { + while (pointOfInstantiation instanceof IASTName) + pointOfInstantiation= pointOfInstantiation.getParent(); ICPPClassType callToObjectOfClassType= null; IType type2= null; if (args.length >= 2) { - type2 = args[1].getTypeOrFunctionSet(point); + type2 = args[1].getTypeOrFunctionSet(pointOfInstantiation); type2= getNestedType(type2, TDEF | REF | CVTYPE); } @@ -3275,7 +3279,7 @@ public class CPPSemantics { return null; if (methodLookupType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) methodLookupType; - methodData = new LookupData(operator.toCharArray(), null, point); + methodData = new LookupData(operator.toCharArray(), null, pointOfInstantiation); methodData.setFunctionArguments(true, args); methodData.qualified = true; // (13.3.1.2.3) @@ -3294,7 +3298,7 @@ public class CPPSemantics { } // Find a function - LookupData funcData = new LookupData(operator.toCharArray(), null, point); + LookupData funcData = new LookupData(operator.toCharArray(), null, pointOfInstantiation); // Global new and delete operators do not take an argument for the this pointer. switch (operator) { @@ -3311,7 +3315,7 @@ public class CPPSemantics { if (mode == LookupMode.ALL_GLOBALS || mode == LookupMode.LIMITED_GLOBALS || (mode == LookupMode.GLOBALS_IF_NO_MEMBERS && !haveMembers)) { try { - IScope scope = CPPVisitor.getContainingScope(point); + IScope scope = CPPVisitor.getContainingScope(pointOfInstantiation); if (scope == null) return null; lookup(funcData, scope); @@ -3319,8 +3323,20 @@ public class CPPSemantics { doKoenigLookup(funcData); } catch (DOMException e) { } + + // Also do a lookup at the point of definition. + if (pointOfDefinition != null) { + LookupData funcData2 = new LookupData(operator.toCharArray(), null, pointOfInstantiation); + funcData2.setFunctionArguments(true, args); + funcData2.ignoreMembers = true; + lookup(funcData2, pointOfDefinition); + if (funcData2.hasResults()) { + mergeResults(funcData, funcData2.foundItems, false); + } + } + // Filter with file-set - IASTTranslationUnit tu= point.getTranslationUnit(); + IASTTranslationUnit tu= pointOfInstantiation.getTranslationUnit(); if (tu != null && funcData.foundItems instanceof Object[]) { final IIndexFileSet fileSet = tu.getIndexFileSet(); if (fileSet != null) { @@ -3395,7 +3411,7 @@ public class CPPSemantics { if (callToObjectOfClassType != null) { try { // 13.3.1.1.2 call to object of class type - ICPPMethod[] ops = SemanticUtil.getConversionOperators(callToObjectOfClassType, point); + ICPPMethod[] ops = SemanticUtil.getConversionOperators(callToObjectOfClassType, pointOfInstantiation); for (ICPPMethod op : ops) { if (op.isExplicit()) continue; @@ -3406,7 +3422,7 @@ public class CPPSemantics { IType ptt= SemanticUtil.getNestedType(((IPointerType) rt).getType(), SemanticUtil.TDEF); if (ptt instanceof IFunctionType) { IFunctionType ft2= (IFunctionType) ptt; - IBinding sf= createSurrogateCallFunction(point.getTranslationUnit().getScope(), ft2.getReturnType(), rt, ft2.getParameterTypes()); + IBinding sf= createSurrogateCallFunction(pointOfInstantiation.getTranslationUnit().getScope(), ft2.getReturnType(), rt, ft2.getParameterTypes()); mergeResults(funcData, sf, false); } } @@ -3418,7 +3434,7 @@ public class CPPSemantics { } if (methodLookupType instanceof ICPPClassType || type2 instanceof ICPPClassType) { - ICPPFunction[] builtins= BuiltinOperators.create(operator, args, point, (Object[]) funcData.foundItems); + ICPPFunction[] builtins= BuiltinOperators.create(operator, args, pointOfInstantiation, (Object[]) funcData.foundItems); mergeResults(funcData, builtins, false); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index a1421067623..0069e6758bf 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -231,7 +231,7 @@ public class CPPTemplates { } if (i < numArgs) { ICPPTemplateArgument arg= arguments[i]; - ICPPTemplateArgument newArg = matchTemplateParameterAndArgument(param, arg, map, point); + ICPPTemplateArgument newArg = matchTemplateParameterAndArgument(template, param, arg, map, point); if (newArg == null) return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point); if (newArg != arg) { @@ -499,12 +499,13 @@ public class CPPTemplates { if (ct instanceof ICPPClassTemplatePartialSpecialization) { args= ((ICPPClassTemplatePartialSpecialization) ct).getTemplateArguments(); } else { - args = templateParametersAsArguments(ct.getTemplateParameters()); + args = templateParametersAsArguments(ct); } return new CPPDeferredClassInstance(ct, args, (ICPPScope) ct.getCompositeScope()); } - public static ICPPTemplateArgument[] templateParametersAsArguments(ICPPTemplateParameter[] tpars) { + public static ICPPTemplateArgument[] templateParametersAsArguments(ICPPClassTemplate template) { + ICPPTemplateParameter[] tpars = template.getTemplateParameters(); ICPPTemplateArgument[] args; args = new ICPPTemplateArgument[tpars.length]; for (int i = 0; i < tpars.length; i++) { @@ -518,7 +519,7 @@ public class CPPTemplates { } else if (tp instanceof ICPPTemplateNonTypeParameter) { // Non-type template parameter pack already has type 'ICPPParameterPackType' final ICPPTemplateNonTypeParameter nttp = (ICPPTemplateNonTypeParameter) tp; - args[i] = new CPPTemplateNonTypeArgument(Value.create(nttp), nttp.getType()); + args[i] = new CPPTemplateNonTypeArgument(Value.create(template, nttp), nttp.getType()); } else { assert false; } @@ -2274,8 +2275,8 @@ public class CPPTemplates { return arg != null && isValidType(arg.isTypeValue() ? arg.getTypeValue() : arg.getTypeOfNonTypeValue()); } - static ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateParameter param, - ICPPTemplateArgument arg, CPPTemplateParameterMap map, IASTNode point) { + static ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateDefinition template, + ICPPTemplateParameter param, ICPPTemplateArgument arg, CPPTemplateParameterMap map, IASTNode point) { if (arg == null || !isValidType(arg.getTypeValue())) { return null; } @@ -2331,7 +2332,7 @@ public class CPPTemplates { if (argType instanceof ICPPUnknownType) { return new CPPTemplateNonTypeArgument(arg.getNonTypeValue(), pType); } - return convertNonTypeTemplateArgument(pType, arg, point); + return convertNonTypeTemplateArgument(template, pType, arg, point); } catch (DOMException e) { return null; } @@ -2399,7 +2400,8 @@ public class CPPTemplates { * specified in 14.3.2 - 5. * @throws DOMException */ - private static ICPPTemplateArgument convertNonTypeTemplateArgument(final IType paramType, ICPPTemplateArgument arg, IASTNode point) throws DOMException { + private static ICPPTemplateArgument convertNonTypeTemplateArgument(ICPPTemplateDefinition template, + final IType paramType, ICPPTemplateArgument arg, IASTNode point) throws DOMException { //14.1s8 function to pointer and array to pointer conversions IType a= arg.getTypeOfNonTypeValue(); IType p; @@ -2422,7 +2424,7 @@ public class CPPTemplates { for (ICPPFunction f : functionSet.getBindings()) { if (p.isSameType(f.getType())) { functionSet.applySelectedFunction(f); - return new CPPTemplateNonTypeArgument(new EvalBinding(f, null), point); + return new CPPTemplateNonTypeArgument(new EvalBinding(f, null, template), point); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java index b80e21c6f32..bb919a9960d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinary.java @@ -46,6 +46,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; @@ -70,7 +71,7 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalBinary extends CPPEvaluation { +public class EvalBinary extends CPPDependentEvaluation { public final static int op_arrayAccess= Byte.MAX_VALUE; private final int fOperator; @@ -80,7 +81,11 @@ public class EvalBinary extends CPPEvaluation { private ICPPFunction fOverload= CPPFunction.UNINITIALIZED_FUNCTION; private IType fType; - public EvalBinary(int operator, ICPPEvaluation arg1, ICPPEvaluation arg2) { + public EvalBinary(int operator, ICPPEvaluation arg1, ICPPEvaluation arg2, IASTNode pointOfDefinition) { + this(operator, arg1, arg2, findEnclosingTemplate(pointOfDefinition)); + } + public EvalBinary(int operator, ICPPEvaluation arg1, ICPPEvaluation arg2, IBinding templateDefinition) { + super(templateDefinition); fOperator= operator; fArg1= arg1; fArg2= arg2; @@ -234,12 +239,14 @@ public class EvalBinary extends CPPEvaluation { IType type = fArg1.getTypeOrFunctionSet(point); type= SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); if (type instanceof ICPPClassType) { - return CPPSemantics.findOverloadedBinaryOperator(point, OverloadableOperator.BRACKET, fArg1, fArg2); + return CPPSemantics.findOverloadedBinaryOperator(point, getTemplateDefinitionScope(), + OverloadableOperator.BRACKET, fArg1, fArg2); } } else { final OverloadableOperator op = OverloadableOperator.fromBinaryExpression(fOperator); if (op != null) { - return CPPSemantics.findOverloadedBinaryOperator(point, op, fArg1, fArg2); + return CPPSemantics.findOverloadedBinaryOperator(point, getTemplateDefinitionScope(), + op, fArg1, fArg2); } } return null; @@ -328,13 +335,15 @@ public class EvalBinary extends CPPEvaluation { buffer.putByte((byte) fOperator); buffer.marshalEvaluation(fArg1, includeValue); buffer.marshalEvaluation(fArg2, includeValue); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { int op= buffer.getByte(); ICPPEvaluation arg1= (ICPPEvaluation) buffer.unmarshalEvaluation(); ICPPEvaluation arg2= (ICPPEvaluation) buffer.unmarshalEvaluation(); - return new EvalBinary(op, arg1, arg2); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalBinary(op, arg1, arg2, templateDefinition); } @Override @@ -344,7 +353,7 @@ public class EvalBinary extends CPPEvaluation { ICPPEvaluation arg2 = fArg2.instantiate(tpMap, packOffset, within, maxdepth, point); if (arg1 == fArg1 && arg2 == fArg2) return this; - return new EvalBinary(fOperator, arg1, arg2); + return new EvalBinary(fOperator, arg1, arg2, getTemplateDefinition()); } @Override @@ -354,7 +363,7 @@ public class EvalBinary extends CPPEvaluation { ICPPEvaluation arg2 = fArg2.computeForFunctionCall(parameterMap, maxdepth, point); if (arg1 == fArg1 && arg2 == fArg2) return this; - return new EvalBinary(fOperator, arg1, arg2); + return new EvalBinary(fOperator, arg1, arg2, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java index 98dac57bcd6..8521bfa51c1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java @@ -16,6 +16,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression.Operator; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -31,14 +32,18 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalBinaryTypeId extends CPPEvaluation { +public class EvalBinaryTypeId extends CPPDependentEvaluation { private final Operator fOperator; private final IType fType1, fType2; private boolean fCheckedValueDependent; private boolean fIsValueDependent; - public EvalBinaryTypeId(Operator kind, IType type1, IType type2) { + public EvalBinaryTypeId(Operator kind, IType type1, IType type2, IASTNode pointOfDefinition) { + this(kind, type1, type2, findEnclosingTemplate(pointOfDefinition)); + } + public EvalBinaryTypeId(Operator kind, IType type1, IType type2, IBinding templateDefinition) { + super(templateDefinition); fOperator= kind; fType1= type1; fType2= type2; @@ -108,13 +113,15 @@ public class EvalBinaryTypeId extends CPPEvaluation { buffer.putByte((byte) fOperator.ordinal()); buffer.marshalType(fType1); buffer.marshalType(fType2); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { int op= buffer.getByte(); IType arg1= buffer.unmarshalType(); IType arg2= buffer.unmarshalType(); - return new EvalBinaryTypeId(Operator.values()[op], arg1, arg2); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalBinaryTypeId(Operator.values()[op], arg1, arg2, templateDefinition); } @Override @@ -124,7 +131,7 @@ public class EvalBinaryTypeId extends CPPEvaluation { IType type2 = CPPTemplates.instantiateType(fType2, tpMap, packOffset, within, point); if (type1 == fType1 && type2 == fType2) return this; - return new EvalBinaryTypeId(fOperator, type1, type2); + return new EvalBinaryTypeId(fOperator, type1, type2, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java index d8567779e1e..17a09e84790 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java @@ -43,7 +43,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.core.runtime.CoreException; -public class EvalBinding extends CPPEvaluation { +public class EvalBinding extends CPPDependentEvaluation { /** * The function owning the parameter if the binding is a function parameter, otherwise * {@code null}. May be computed lazily and remains {@code null} until computed. @@ -68,14 +68,22 @@ public class EvalBinding extends CPPEvaluation { private boolean fIsTypeDependent; private boolean fCheckedIsTypeDependent; - public EvalBinding(IBinding binding, IType type) { + public EvalBinding(IBinding binding, IType type, IASTNode pointOfDefinition) { + this(binding, type, findEnclosingTemplate(pointOfDefinition)); + } + public EvalBinding(IBinding binding, IType type, IBinding templateDefinition) { + super(templateDefinition); fParameterPosition = -1; fBinding= binding; fType= type; fFixedType= type != null; } - public EvalBinding(ICPPFunction parameterOwner, int parameterPosition, IType type) { + public EvalBinding(ICPPFunction parameterOwner, int parameterPosition, IType type, IASTNode pointOfDefinition) { + this(parameterOwner, parameterPosition, type, findEnclosingTemplate(pointOfDefinition)); + } + public EvalBinding(ICPPFunction parameterOwner, int parameterPosition, IType type, IBinding templateDefinition) { + super(templateDefinition); fParameterOwner = parameterOwner; fParameterPosition = parameterPosition; fType= type; @@ -298,6 +306,7 @@ public class EvalBinding extends CPPEvaluation { buffer.marshalBinding(fBinding); } buffer.marshalType(fFixedType ? fType : null); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -305,11 +314,13 @@ public class EvalBinding extends CPPEvaluation { ICPPFunction parameterOwner= (ICPPFunction) buffer.unmarshalBinding(); int parameterPosition= buffer.getInt(); IType type= buffer.unmarshalType(); - return new EvalBinding(parameterOwner, parameterPosition, type); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalBinding(parameterOwner, parameterPosition, type, templateDefinition); } else { IBinding binding= buffer.unmarshalBinding(); IType type= buffer.unmarshalType(); - return new EvalBinding(binding, type); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalBinding(binding, type, templateDefinition); } } @@ -333,7 +344,7 @@ public class EvalBinding extends CPPEvaluation { } else { IBinding instantiatedBinding = instantiateBinding(origBinding, tpMap, packOffset, within, maxdepth, point); if (instantiatedBinding != origBinding) - return new EvalBinding(instantiatedBinding, null); + return new EvalBinding(instantiatedBinding, null, getTemplateDefinition()); } return this; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java index b1821c5926a..889a2f0ce07 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalComma.java @@ -16,6 +16,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionT import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; @@ -28,7 +29,7 @@ import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.core.runtime.CoreException; -public class EvalComma extends CPPEvaluation { +public class EvalComma extends CPPDependentEvaluation { private static final ICPPFunction[] NO_FUNCTIONS = {}; private final ICPPEvaluation[] fArguments; @@ -36,7 +37,11 @@ public class EvalComma extends CPPEvaluation { private IType fType; - public EvalComma(ICPPEvaluation[] evals) { + public EvalComma(ICPPEvaluation[] evals, IASTNode pointOfDefinition) { + this(evals, findEnclosingTemplate(pointOfDefinition)); + } + public EvalComma(ICPPEvaluation[] evals, IBinding templateDefinition) { + super(templateDefinition); fArguments= evals; } @@ -93,7 +98,7 @@ public class EvalComma extends CPPEvaluation { ICPPEvaluation e1= fArguments[0]; for (int i = 1; i < fArguments.length; i++) { ICPPEvaluation e2 = fArguments[i]; - ICPPFunction overload = CPPSemantics.findOverloadedOperatorComma(point, e1, e2); + ICPPFunction overload = CPPSemantics.findOverloadedOperatorComma(point, getTemplateDefinitionScope(), e1, e2); if (overload == null) { e1= e2; } else { @@ -159,6 +164,7 @@ public class EvalComma extends CPPEvaluation { for (ICPPEvaluation arg : fArguments) { buffer.marshalEvaluation(arg, includeValue); } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -167,7 +173,8 @@ public class EvalComma extends CPPEvaluation { for (int i = 0; i < args.length; i++) { args[i]= (ICPPEvaluation) buffer.unmarshalEvaluation(); } - return new EvalComma(args); + IBinding templateDefinition = buffer.unmarshalBinding(); + return new EvalComma(args, templateDefinition); } @Override @@ -186,7 +193,7 @@ public class EvalComma extends CPPEvaluation { } if (args == fArguments) return this; - return new EvalComma(args); + return new EvalComma(args, getTemplateDefinition()); } @Override @@ -205,7 +212,7 @@ public class EvalComma extends CPPEvaluation { } if (args == fArguments) return this; - return new EvalComma(args); + return new EvalComma(args, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompound.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompound.java index 280e0f05d4b..6e8f0486710 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompound.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalCompound.java @@ -15,6 +15,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -28,10 +29,14 @@ import org.eclipse.core.runtime.CoreException; * Performs evaluation of a compound statement expression. Most but not all methods * delegate to the evaluation of the last expression in the compound one. */ -public class EvalCompound extends CPPEvaluation { +public class EvalCompound extends CPPDependentEvaluation { private final ICPPEvaluation fDelegate; - public EvalCompound(ICPPEvaluation delegate) { + public EvalCompound(ICPPEvaluation delegate, IASTNode pointOfDefinition) { + this(delegate, findEnclosingTemplate(pointOfDefinition)); + } + public EvalCompound(ICPPEvaluation delegate, IBinding templateDefinition) { + super(templateDefinition); fDelegate= delegate; } @@ -78,11 +83,13 @@ public class EvalCompound extends CPPEvaluation { public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { buffer.putByte(ITypeMarshalBuffer.EVAL_COMPOUND); buffer.marshalEvaluation(fDelegate, includeValue); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { ICPPEvaluation arg= (ICPPEvaluation) buffer.unmarshalEvaluation(); - return new EvalCompound(arg); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalCompound(arg, templateDefinition); } @Override @@ -91,7 +98,7 @@ public class EvalCompound extends CPPEvaluation { ICPPEvaluation delegate = fDelegate.instantiate(tpMap, packOffset, within, maxdepth, point); if (delegate == fDelegate) return this; - return new EvalCompound(delegate); + return new EvalCompound(delegate, getTemplateDefinition()); } @Override @@ -100,7 +107,7 @@ public class EvalCompound extends CPPEvaluation { ICPPEvaluation delegate = fDelegate.computeForFunctionCall(parameterMap, maxdepth, point); if (delegate == fDelegate) return this; - return new EvalCompound(delegate); + return new EvalCompound(delegate, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java index 393c1f7c372..c130d0f763b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalConditional.java @@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; @@ -47,7 +48,7 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalConditional extends CPPEvaluation { +public class EvalConditional extends CPPDependentEvaluation { private final ICPPEvaluation fCondition, fPositive, fNegative; private final boolean fPositiveThrows, fNegativeThrows; @@ -56,7 +57,12 @@ public class EvalConditional extends CPPEvaluation { private ICPPFunction fOverload; public EvalConditional(ICPPEvaluation condition, ICPPEvaluation positive, ICPPEvaluation negative, - boolean positiveThrows, boolean negativeThrows) { + boolean positiveThrows, boolean negativeThrows, IASTNode pointOfDefinition) { + this(condition, positive, negative, positiveThrows, negativeThrows, findEnclosingTemplate(pointOfDefinition)); + } + public EvalConditional(ICPPEvaluation condition, ICPPEvaluation positive, ICPPEvaluation negative, + boolean positiveThrows, boolean negativeThrows, IBinding templateDefinition) { + super(templateDefinition); // Gnu-extension: Empty positive expression is replaced by condition. fCondition= condition; fPositive= positive; @@ -229,7 +235,7 @@ public class EvalConditional extends CPPEvaluation { // 5.16-5: At least one class type but no conversion if (isClassType2 || isClassType3) { - fOverload = CPPSemantics.findOverloadedConditionalOperator(point, positive, fNegative); + fOverload = CPPSemantics.findOverloadedConditionalOperator(point, getTemplateDefinitionScope(), positive, fNegative); if (fOverload != null) { fType= ExpressionTypes.typeFromFunctionCall(fOverload); } else { @@ -313,6 +319,7 @@ public class EvalConditional extends CPPEvaluation { buffer.marshalEvaluation(fCondition, includeValue); buffer.marshalEvaluation(fPositive, includeValue); buffer.marshalEvaluation(fNegative, includeValue); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -321,7 +328,8 @@ public class EvalConditional extends CPPEvaluation { ICPPEvaluation cond= (ICPPEvaluation) buffer.unmarshalEvaluation(); ICPPEvaluation pos= (ICPPEvaluation) buffer.unmarshalEvaluation(); ICPPEvaluation neg= (ICPPEvaluation) buffer.unmarshalEvaluation(); - return new EvalConditional(cond, pos, neg, pth, nth); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalConditional(cond, pos, neg, pth, nth, templateDefinition); } @Override @@ -333,7 +341,7 @@ public class EvalConditional extends CPPEvaluation { ICPPEvaluation negative = fNegative.instantiate(tpMap, packOffset, within, maxdepth, point); if (condition == fCondition && positive == fPositive && negative == fNegative) return this; - return new EvalConditional(condition, positive, negative, fPositiveThrows, fNegativeThrows); + return new EvalConditional(condition, positive, negative, fPositiveThrows, fNegativeThrows, getTemplateDefinition()); } @Override @@ -345,7 +353,7 @@ public class EvalConditional extends CPPEvaluation { ICPPEvaluation negative = fNegative.computeForFunctionCall(parameterMap, maxdepth, point); if (condition == fCondition && positive == fPositive && negative == fNegative) return this; - return new EvalConditional(condition, positive, negative, fPositiveThrows, fNegativeThrows); + return new EvalConditional(condition, positive, negative, fPositiveThrows, fNegativeThrows, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java index 5636cf9bf2f..7df4e724073 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java @@ -43,12 +43,16 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.LookupMode; import org.eclipse.core.runtime.CoreException; -public class EvalFunctionCall extends CPPEvaluation { +public class EvalFunctionCall extends CPPDependentEvaluation { private final ICPPEvaluation[] fArguments; private ICPPFunction fOverload= CPPFunction.UNINITIALIZED_FUNCTION; private IType fType; - public EvalFunctionCall(ICPPEvaluation[] args) { + public EvalFunctionCall(ICPPEvaluation[] args, IASTNode pointOfDefinition) { + this(args, findEnclosingTemplate(pointOfDefinition)); + } + public EvalFunctionCall(ICPPEvaluation[] args, IBinding templateDefinition) { + super(templateDefinition); fArguments= args; } @@ -101,7 +105,8 @@ public class EvalFunctionCall extends CPPEvaluation { IType t= SemanticUtil.getNestedType(fArguments[0].getTypeOrFunctionSet(point), TDEF | REF | CVTYPE); if (t instanceof ICPPClassType) { - return CPPSemantics.findOverloadedOperator(point, fArguments, t, OverloadableOperator.PAREN, LookupMode.NO_GLOBALS); + return CPPSemantics.findOverloadedOperator(point, getTemplateDefinitionScope(), fArguments, t, + OverloadableOperator.PAREN, LookupMode.NO_GLOBALS); } return null; } @@ -174,6 +179,7 @@ public class EvalFunctionCall extends CPPEvaluation { for (ICPPEvaluation arg : fArguments) { buffer.marshalEvaluation(arg, includeValue); } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -182,7 +188,8 @@ public class EvalFunctionCall extends CPPEvaluation { for (int i = 0; i < args.length; i++) { args[i]= (ICPPEvaluation) buffer.unmarshalEvaluation(); } - return new EvalFunctionCall(args); + IBinding templateDefinition = buffer.unmarshalBinding(); + return new EvalFunctionCall(args, templateDefinition); } @Override @@ -206,7 +213,7 @@ public class EvalFunctionCall extends CPPEvaluation { // Resolve the function using the parameters of the function call. args[0] = ((EvalFunctionSet) args[0]).resolveFunction(Arrays.copyOfRange(args, 1, args.length), point); } - return new EvalFunctionCall(args); + return new EvalFunctionCall(args, getTemplateDefinition()); } @Override @@ -228,7 +235,7 @@ public class EvalFunctionCall extends CPPEvaluation { } EvalFunctionCall eval = this; if (args != fArguments) - eval = new EvalFunctionCall(args); + eval = new EvalFunctionCall(args, getTemplateDefinition()); return eval.computeForFunctionCall(maxdepth - 1, point); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java index 60771fd3cfe..a267dd3f409 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java @@ -38,11 +38,15 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalFunctionSet extends CPPEvaluation { +public class EvalFunctionSet extends CPPDependentEvaluation { private final CPPFunctionSet fFunctionSet; private final boolean fAddressOf; - public EvalFunctionSet(CPPFunctionSet set, boolean addressOf) { + public EvalFunctionSet(CPPFunctionSet set, boolean addressOf, IASTNode pointOfDefinition) { + this(set, addressOf, findEnclosingTemplate(pointOfDefinition)); + } + public EvalFunctionSet(CPPFunctionSet set, boolean addressOf, IBinding templateDefinition) { + super(templateDefinition); fFunctionSet= set; fAddressOf= addressOf; } @@ -122,6 +126,7 @@ public class EvalFunctionSet extends CPPEvaluation { buffer.marshalTemplateArgument(arg); } } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -139,7 +144,8 @@ public class EvalFunctionSet extends CPPEvaluation { args[i]= buffer.unmarshalTemplateArgument(); } } - return new EvalFunctionSet(new CPPFunctionSet(bindings, args, null), addressOf); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalFunctionSet(new CPPFunctionSet(bindings, args, null), addressOf, templateDefinition); } @Override @@ -173,7 +179,7 @@ public class EvalFunctionSet extends CPPEvaluation { } if (Arrays.equals(arguments, originalArguments) && functions == originalFunctions) return this; - return new EvalFunctionSet(new CPPFunctionSet(functions, arguments, null), fAddressOf); + return new EvalFunctionSet(new CPPFunctionSet(functions, arguments, null), fAddressOf, getTemplateDefinition()); } @Override @@ -198,7 +204,7 @@ public class EvalFunctionSet extends CPPEvaluation { try { IBinding binding = CPPSemantics.resolveFunction(data, functions, true); if (binding instanceof ICPPFunction && !(binding instanceof ICPPUnknownBinding)) - return new EvalBinding(binding, null); + return new EvalBinding(binding, null, getTemplateDefinition()); } catch (DOMException e) { CCorePlugin.log(e); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java index 61c5c7883af..49960745ddc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java @@ -54,7 +54,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.core.runtime.CoreException; -public class EvalID extends CPPEvaluation { +public class EvalID extends CPPDependentEvaluation { private final ICPPEvaluation fFieldOwner; private final char[] fName; private final IBinding fNameOwner; @@ -63,7 +63,12 @@ public class EvalID extends CPPEvaluation { private final ICPPTemplateArgument[] fTemplateArgs; public EvalID(ICPPEvaluation fieldOwner, IBinding nameOwner, char[] simpleID, boolean addressOf, - boolean qualified, ICPPTemplateArgument[] templateArgs) { + boolean qualified, ICPPTemplateArgument[] templateArgs, IASTNode pointOfDefinition) { + this(fieldOwner, nameOwner, simpleID, addressOf, qualified, templateArgs, findEnclosingTemplate(pointOfDefinition)); + } + public EvalID(ICPPEvaluation fieldOwner, IBinding nameOwner, char[] simpleID, boolean addressOf, + boolean qualified, ICPPTemplateArgument[] templateArgs, IBinding templateDefinition) { + super(templateDefinition); fFieldOwner= fieldOwner; fName= simpleID; fNameOwner= nameOwner; @@ -158,6 +163,7 @@ public class EvalID extends CPPEvaluation { buffer.marshalTemplateArgument(arg); } } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -174,7 +180,8 @@ public class EvalID extends CPPEvaluation { args[i]= buffer.unmarshalTemplateArgument(); } } - return new EvalID(fieldOwner, nameOwner, name, addressOf, qualified, args); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalID(fieldOwner, nameOwner, name, addressOf, qualified, args, templateDefinition); } public static ICPPEvaluation create(IASTIdExpression expr) { @@ -183,7 +190,7 @@ public class EvalID extends CPPEvaluation { if (binding instanceof IProblemBinding || binding instanceof IType || binding instanceof ICPPConstructor) return EvalFixed.INCOMPLETE; if (binding instanceof CPPFunctionSet) { - return new EvalFunctionSet((CPPFunctionSet) binding, isAddressOf(expr)); + return new EvalFunctionSet((CPPFunctionSet) binding, isAddressOf(expr), expr); } if (binding instanceof ICPPUnknownBinding) { ICPPTemplateArgument[] templateArgs = null; @@ -200,7 +207,7 @@ public class EvalID extends CPPEvaluation { CPPDeferredFunction deferredFunction = (CPPDeferredFunction) binding; if (deferredFunction.getCandidates() != null) { CPPFunctionSet functionSet = new CPPFunctionSet(deferredFunction.getCandidates(), templateArgs, null); - return new EvalFunctionSet(functionSet, isAddressOf(expr)); + return new EvalFunctionSet(functionSet, isAddressOf(expr), expr); } } @@ -215,7 +222,7 @@ public class EvalID extends CPPEvaluation { } return new EvalID(fieldOwner, owner, name.getSimpleID(), isAddressOf(expr), - name instanceof ICPPASTQualifiedName, templateArgs); + name instanceof ICPPASTQualifiedName, templateArgs, expr); } /** * 9.3.1-3 Transformation to class member access within a non-static member function. @@ -224,7 +231,7 @@ public class EvalID extends CPPEvaluation { && !(binding instanceof ICPPConstructor) &&!((ICPPMember) binding).isStatic()) { IType fieldOwnerType= withinNonStaticMethod(expr); if (fieldOwnerType != null) { - return new EvalMemberAccess(fieldOwnerType, LVALUE, binding, true); + return new EvalMemberAccess(fieldOwnerType, LVALUE, binding, true, expr); } } @@ -241,14 +248,14 @@ public class EvalID extends CPPEvaluation { // of the enumerator. type= CPPSemantics.INT_TYPE; } - return new EvalBinding(binding, type); + return new EvalBinding(binding, type, expr); } } - return new EvalBinding(binding, null); + return new EvalBinding(binding, null, expr); } if (binding instanceof ICPPTemplateNonTypeParameter || binding instanceof IVariable || binding instanceof IFunction) { - return new EvalBinding(binding, null); + return new EvalBinding(binding, null, expr); } return EvalFixed.INCOMPLETE; } @@ -318,7 +325,7 @@ public class EvalID extends CPPEvaluation { return eval; } - return new EvalID(fieldOwner, nameOwner, fName, fAddressOf, fQualified, templateArgs); + return new EvalID(fieldOwner, nameOwner, fName, fAddressOf, fQualified, templateArgs, getTemplateDefinition()); } @Override @@ -329,7 +336,7 @@ public class EvalID extends CPPEvaluation { ICPPEvaluation fieldOwner = fFieldOwner.computeForFunctionCall(parameterMap, maxdepth, point); if (fieldOwner == fFieldOwner) return this; - return new EvalID(fieldOwner, fNameOwner, fName, fAddressOf, fQualified, fTemplateArgs); + return new EvalID(fieldOwner, fNameOwner, fName, fAddressOf, fQualified, fTemplateArgs, getTemplateDefinition()); } private ICPPEvaluation resolveName(ICPPClassType nameOwner, ICPPTemplateArgument[] templateArgs, @@ -344,15 +351,15 @@ public class EvalID extends CPPEvaluation { if (bindings.length > 1 && bindings[0] instanceof ICPPFunction) { ICPPFunction[] functions = new ICPPFunction[bindings.length]; System.arraycopy(bindings, 0, functions, 0, bindings.length); - return new EvalFunctionSet(new CPPFunctionSet(functions, templateArgs, null), fAddressOf); + return new EvalFunctionSet(new CPPFunctionSet(functions, templateArgs, null), fAddressOf, getTemplateDefinition()); } IBinding binding = bindings.length == 1 ? bindings[0] : null; if (binding instanceof IEnumerator) { - return new EvalBinding(binding, null); + return new EvalBinding(binding, null, getTemplateDefinition()); } else if (binding instanceof ICPPMember) { - return new EvalMemberAccess(nameOwner, ValueCategory.PRVALUE, binding, false); + return new EvalMemberAccess(nameOwner, ValueCategory.PRVALUE, binding, false, getTemplateDefinition()); } else if (binding instanceof CPPFunctionSet) { - return new EvalFunctionSet((CPPFunctionSet) binding, fAddressOf); + return new EvalFunctionSet((CPPFunctionSet) binding, fAddressOf, getTemplateDefinition()); } return null; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java index 09355929a34..8364ff49b94 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalInitList.java @@ -15,6 +15,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -28,10 +29,14 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalInitList extends CPPEvaluation { +public class EvalInitList extends CPPDependentEvaluation { private final ICPPEvaluation[] fClauses; - public EvalInitList(ICPPEvaluation[] clauses) { + public EvalInitList(ICPPEvaluation[] clauses, IASTNode pointOfDefinition) { + this(clauses, findEnclosingTemplate(pointOfDefinition)); + } + public EvalInitList(ICPPEvaluation[] clauses, IBinding templateDefinition) { + super(templateDefinition); fClauses= clauses; } @@ -91,6 +96,7 @@ public class EvalInitList extends CPPEvaluation { for (ICPPEvaluation arg : fClauses) { buffer.marshalEvaluation(arg, includeValue); } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -99,7 +105,8 @@ public class EvalInitList extends CPPEvaluation { for (int i = 0; i < args.length; i++) { args[i]= (ICPPEvaluation) buffer.unmarshalEvaluation(); } - return new EvalInitList(args); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalInitList(args, templateDefinition); } @Override @@ -118,7 +125,7 @@ public class EvalInitList extends CPPEvaluation { } if (clauses == fClauses) return this; - return new EvalInitList(clauses); + return new EvalInitList(clauses, getTemplateDefinition()); } @Override @@ -137,7 +144,7 @@ public class EvalInitList extends CPPEvaluation { } if (clauses == fClauses) return this; - return new EvalInitList(clauses); + return new EvalInitList(clauses, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java index 88d935356fb..240ab162e65 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalMemberAccess.java @@ -54,7 +54,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.LookupMode; import org.eclipse.core.runtime.CoreException; -public class EvalMemberAccess extends CPPEvaluation { +public class EvalMemberAccess extends CPPDependentEvaluation { private final IType fOwnerType; private final IBinding fMember; private final ValueCategory fOwnerValueCategory; @@ -67,7 +67,12 @@ public class EvalMemberAccess extends CPPEvaluation { private boolean fCheckedIsValueDependent; public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, - boolean isPointerDeref) { + boolean isPointerDeref, IASTNode pointOfDefinition) { + this(ownerType, ownerValueCat, member, isPointerDeref, findEnclosingTemplate(pointOfDefinition)); + } + public EvalMemberAccess(IType ownerType, ValueCategory ownerValueCat, IBinding member, + boolean isPointerDeref, IBinding templateDefinition) { + super(templateDefinition); fOwnerType= ownerType; fOwnerValueCategory= ownerValueCat; fMember= member; @@ -176,7 +181,7 @@ public class EvalMemberAccess extends CPPEvaluation { */ ICPPEvaluation[] args= { new EvalFixed(type, LVALUE, Value.UNKNOWN) }; - ICPPFunction op= CPPSemantics.findOverloadedOperator(point, args, classType, + ICPPFunction op= CPPSemantics.findOverloadedOperator(point, null, args, classType, OverloadableOperator.ARROW, LookupMode.NO_GLOBALS); if (op == null) break; @@ -302,6 +307,7 @@ public class EvalMemberAccess extends CPPEvaluation { buffer.putByte((byte) firstByte); buffer.marshalType(fOwnerType); buffer.marshalBinding(fMember); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -317,7 +323,8 @@ public class EvalMemberAccess extends CPPEvaluation { IType ownerType= buffer.unmarshalType(); IBinding member= buffer.unmarshalBinding(); - return new EvalMemberAccess(ownerType, ownerValueCat, member, isDeref); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalMemberAccess(ownerType, ownerValueCat, member, isDeref, templateDefinition); } @Override @@ -331,7 +338,7 @@ public class EvalMemberAccess extends CPPEvaluation { if (ownerType instanceof ICPPClassSpecialization) { member = CPPTemplates.createSpecialization((ICPPClassSpecialization) ownerType, fMember, point); } - return new EvalMemberAccess(ownerType, fOwnerValueCategory, member, fIsPointerDeref); + return new EvalMemberAccess(ownerType, fOwnerValueCategory, member, fIsPointerDeref, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java index b00f13229f3..60b06027cd3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java @@ -16,6 +16,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionT import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -30,14 +31,18 @@ import org.eclipse.core.runtime.CoreException; /** * Performs evaluation of an expression. */ -public class EvalTypeId extends CPPEvaluation { +public class EvalTypeId extends CPPDependentEvaluation { private final IType fInputType; private final ICPPEvaluation[] fArguments; private IType fOutputType; - public EvalTypeId(IType type, ICPPEvaluation... argument) { + public EvalTypeId(IType type, IASTNode pointOfDefinition, ICPPEvaluation... arguments) { + this(type, findEnclosingTemplate(pointOfDefinition), arguments); + } + public EvalTypeId(IType type, IBinding templateDefinition, ICPPEvaluation... arguments) { + super(templateDefinition); fInputType= type; - fArguments= argument; + fArguments= arguments; } public IType getInputType() { @@ -128,6 +133,7 @@ public class EvalTypeId extends CPPEvaluation { buffer.marshalEvaluation(arg, includeValue); } } + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { @@ -140,7 +146,8 @@ public class EvalTypeId extends CPPEvaluation { args[i]= (ICPPEvaluation) buffer.unmarshalEvaluation(); } } - return new EvalTypeId(type, args); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalTypeId(type, templateDefinition, args); } @Override @@ -162,7 +169,7 @@ public class EvalTypeId extends CPPEvaluation { IType type = CPPTemplates.instantiateType(fInputType, tpMap, packOffset, within, point); if (args == fArguments && type == fInputType) return this; - return new EvalTypeId(type, args); + return new EvalTypeId(type, getTemplateDefinition(), args); } @Override @@ -183,7 +190,7 @@ public class EvalTypeId extends CPPEvaluation { } if (args == fArguments) return this; - return new EvalTypeId(fInputType, args); + return new EvalTypeId(fInputType, getTemplateDefinition(), args); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java index a2d61ae8497..f3dc221be57 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java @@ -66,7 +66,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics.LookupMode; import org.eclipse.core.runtime.CoreException; -public class EvalUnary extends CPPEvaluation { +public class EvalUnary extends CPPDependentEvaluation { private static final ICPPEvaluation ZERO_EVAL = new EvalFixed(CPPSemantics.INT_TYPE, PRVALUE, Value.create(0)); private final int fOperator; @@ -75,7 +75,13 @@ public class EvalUnary extends CPPEvaluation { private ICPPFunction fOverload= CPPFunction.UNINITIALIZED_FUNCTION; private IType fType; - public EvalUnary(int operator, ICPPEvaluation operand, IBinding addressOfQualifiedNameBinding) { + public EvalUnary(int operator, ICPPEvaluation operand, IBinding addressOfQualifiedNameBinding, + IASTNode pointOfDefinition) { + this(operator, operand, addressOfQualifiedNameBinding, findEnclosingTemplate(pointOfDefinition)); + } + public EvalUnary(int operator, ICPPEvaluation operand, IBinding addressOfQualifiedNameBinding, + IBinding templateDefinition) { + super(templateDefinition); fOperator= operator; fArgument= operand; fAddressOfQualifiedNameBinding= addressOfQualifiedNameBinding; @@ -170,7 +176,7 @@ public class EvalUnary extends CPPEvaluation { } else { args = new ICPPEvaluation[] { fArgument }; } - return CPPSemantics.findOverloadedOperator(point, args, type, op, LookupMode.LIMITED_GLOBALS); + return CPPSemantics.findOverloadedOperator(point, getTemplateDefinitionScope(), args, type, op, LookupMode.LIMITED_GLOBALS); } @Override @@ -298,13 +304,15 @@ public class EvalUnary extends CPPEvaluation { buffer.putByte((byte) fOperator); buffer.marshalEvaluation(fArgument, includeValue); buffer.marshalBinding(fAddressOfQualifiedNameBinding); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { int op= buffer.getByte(); ICPPEvaluation arg= (ICPPEvaluation) buffer.unmarshalEvaluation(); IBinding binding= buffer.unmarshalBinding(); - return new EvalUnary(op, arg, binding); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalUnary(op, arg, binding, templateDefinition); } @Override @@ -321,7 +329,7 @@ public class EvalUnary extends CPPEvaluation { if (argument == fArgument && aoqn == fAddressOfQualifiedNameBinding) return this; - return new EvalUnary(fOperator, argument, aoqn); + return new EvalUnary(fOperator, argument, aoqn, getTemplateDefinition()); } @Override @@ -331,7 +339,7 @@ public class EvalUnary extends CPPEvaluation { if (argument == fArgument) return this; - return new EvalUnary(fOperator, argument, fAddressOfQualifiedNameBinding); + return new EvalUnary(fOperator, argument, fAddressOfQualifiedNameBinding, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java index 9d2e39b7e52..c7ade038d89 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java @@ -37,6 +37,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -49,12 +50,16 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.core.runtime.CoreException; -public class EvalUnaryTypeID extends CPPEvaluation { +public class EvalUnaryTypeID extends CPPDependentEvaluation { private final int fOperator; private final IType fOrigType; private IType fType; - public EvalUnaryTypeID(int operator, IType type) { + public EvalUnaryTypeID(int operator, IType type, IASTNode pointOfDefinition) { + this(operator, type, findEnclosingTemplate(pointOfDefinition)); + } + public EvalUnaryTypeID(int operator, IType type, IBinding templateDefinition) { + super(templateDefinition); fOperator= operator; fOrigType= type; } @@ -173,12 +178,14 @@ public class EvalUnaryTypeID extends CPPEvaluation { buffer.putByte(ITypeMarshalBuffer.EVAL_UNARY_TYPE_ID); buffer.putByte((byte) fOperator); buffer.marshalType(fOrigType); + marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException { int op= buffer.getByte(); IType arg= buffer.unmarshalType(); - return new EvalUnaryTypeID(op, arg); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalUnaryTypeID(op, arg, templateDefinition); } @Override @@ -187,7 +194,7 @@ public class EvalUnaryTypeID extends CPPEvaluation { IType type = CPPTemplates.instantiateType(fOrigType, tpMap, packOffset, within, point); if (type == fOrigType) return this; - return new EvalUnaryTypeID(fOperator, type); + return new EvalUnaryTypeID(fOperator, type, getTemplateDefinition()); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index 8d33b882c8d..f03403601e6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -90,7 +90,7 @@ public class TemplateArgumentDeduction { CPPTemplateParameterMap map, IASTNode point) throws DOMException { final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); - if (tmplArgs != null && !addExplicitArguments(tmplParams, tmplArgs, map, point)) + if (tmplArgs != null && !addExplicitArguments(template, tmplParams, tmplArgs, map, point)) return null; if (!deduceFromFunctionArgs(template, fnArgs, argIsLValue, map, point)) @@ -315,7 +315,7 @@ public class TemplateArgumentDeduction { static ICPPTemplateArgument[] deduceForAddressOf(ICPPFunctionTemplate template, ICPPTemplateArgument[] tmplArgs, IFunctionType arg, CPPTemplateParameterMap map, IASTNode point) throws DOMException { final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); - if (!addExplicitArguments(tmplParams, tmplArgs, map, point)) + if (!addExplicitArguments(template, tmplParams, tmplArgs, map, point)) return null; IType par= template.getType(); @@ -387,7 +387,7 @@ public class TemplateArgumentDeduction { ICPPTemplateArgument[] args, ICPPFunctionType ftype, CPPTemplateParameterMap map, IASTNode point) throws DOMException { final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); - if (!addExplicitArguments(tmplParams, args, map, point)) + if (!addExplicitArguments(template, tmplParams, args, map, point)) return null; IType a= SemanticUtil.getSimplifiedType(ftype); @@ -479,7 +479,7 @@ public class TemplateArgumentDeduction { /** * Adds the explicit arguments to the map. */ - public static boolean addExplicitArguments(final ICPPTemplateParameter[] tmplParams, + public static boolean addExplicitArguments(ICPPFunctionTemplate template, final ICPPTemplateParameter[] tmplParams, ICPPTemplateArgument[] tmplArgs, CPPTemplateParameterMap map, IASTNode point) { tmplArgs= SemanticUtil.getSimplifiedArguments(tmplArgs); ICPPTemplateParameter tmplParam= null; @@ -495,7 +495,7 @@ public class TemplateArgumentDeduction { } } ICPPTemplateArgument tmplArg= tmplArgs[i]; - tmplArg= CPPTemplates.matchTemplateParameterAndArgument(tmplParam, tmplArg, map, point); + tmplArg= CPPTemplates.matchTemplateParameterAndArgument(template, tmplParam, tmplArg, map, point); if (tmplArg == null) return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java index 32d8fe65cdc..3589b59cfa7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java @@ -232,6 +232,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { public ICPPEvaluation getCompositeEvaluation(ICPPEvaluation eval) { if (eval == null) return null; + IBinding templateDefinition = eval.getTemplateDefinition(); + IBinding templateDefinition2 = getCompositeBinding((IIndexFragmentBinding) templateDefinition); if (eval instanceof EvalBinary) { EvalBinary e= (EvalBinary) eval; ICPPEvaluation a = e.getArg1(); @@ -239,8 +241,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPEvaluation a2 = getCompositeEvaluation(a); ICPPEvaluation b2 = getCompositeEvaluation(b); - if (a != a2 || b != b2) - e= new EvalBinary(e.getOperator(), a2, b2); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalBinary(e.getOperator(), a2, b2, templateDefinition2); return e; } if (eval instanceof EvalBinaryTypeId) { @@ -250,8 +252,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { IType a2 = getCompositeType(a); IType b2 = getCompositeType(b); - if (a != a2 || b != b2) - e= new EvalBinaryTypeId(e.getOperator(), a2, b2); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalBinaryTypeId(e.getOperator(), a2, b2, templateDefinition2); return e; } if (eval instanceof EvalBinding) { @@ -261,9 +263,9 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { IType b = e.getFixedType(); IBinding a2 = getCompositeBinding((IIndexFragmentBinding) parameterOwner); IType b2 = getCompositeType(b); - if (parameterOwner != a2 || b != b2) { + if (parameterOwner != a2 || b != b2 || templateDefinition != templateDefinition2) { int parameterPosition = e.getFunctionParameterPosition(); - e= new EvalBinding((ICPPFunction) a2, parameterPosition, b2); + e= new EvalBinding((ICPPFunction) a2, parameterPosition, b2, templateDefinition2); } } else { IBinding a = e.getBinding(); @@ -271,25 +273,27 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { IBinding a2 = getCompositeBinding((IIndexFragmentBinding) a); IType b2 = getCompositeType(b); - if (a != a2 || b != b2) - e= new EvalBinding(a2, b2); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalBinding(a2, b2, templateDefinition2); } return e; } if (eval instanceof EvalComma) { EvalComma e= (EvalComma) eval; ICPPEvaluation[] a = e.getArguments(); + ICPPEvaluation[] a2 = getCompositeEvaluationArray(a); - if (a != a2) - e= new EvalComma(a2); + + if (a != a2 || templateDefinition != templateDefinition2) + e= new EvalComma(a2, templateDefinition2); return e; } if (eval instanceof EvalCompound) { EvalCompound e= (EvalCompound) eval; ICPPEvaluation a = e.getLastEvaluation(); ICPPEvaluation a2 = getCompositeEvaluation(a); - if (a != a2) - e= new EvalCompound(a2); + if (a != a2 || templateDefinition != templateDefinition2) + e= new EvalCompound(a2, templateDefinition2); return e; } if (eval instanceof EvalConditional) { @@ -300,8 +304,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPEvaluation a2 = getCompositeEvaluation(a); ICPPEvaluation b2 = getCompositeEvaluation(b); ICPPEvaluation c2 = getCompositeEvaluation(c); - if (a != a2 || b != b2 || c != c2) - e= new EvalConditional(a2, b2, c2, e.isPositiveThrows(), e.isNegativeThrows()); + if (a != a2 || b != b2 || c != c2 || templateDefinition != templateDefinition2) + e= new EvalConditional(a2, b2, c2, e.isPositiveThrows(), e.isNegativeThrows(), templateDefinition2); return e; } if (eval instanceof EvalFixed) { @@ -310,7 +314,7 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { IValue b = e.getValue(); IType a2 = getCompositeType(a); IValue b2= getCompositeValue(b); - if (a != a2 || b != b2) + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) e= new EvalFixed(a2, e.getValueCategory(), b2); return e; } @@ -318,8 +322,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { EvalFunctionCall e= (EvalFunctionCall) eval; ICPPEvaluation[] a = e.getArguments(); ICPPEvaluation[] a2 = getCompositeEvaluationArray(a); - if (a != a2) - e= new EvalFunctionCall(a2); + if (a != a2 || templateDefinition != templateDefinition2) + e= new EvalFunctionCall(a2, templateDefinition2); return e; } if (eval instanceof EvalFunctionSet) { @@ -330,8 +334,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPFunction[] a2 = getCompositeFunctionArray(a); ICPPTemplateArgument[] b2 = TemplateInstanceUtil.convert(this, b); - if (a != a2 || b != b2) - e= new EvalFunctionSet(new CPPFunctionSet(a2, b2, null), e.isAddressOf()); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalFunctionSet(new CPPFunctionSet(a2, b2, null), e.isAddressOf(), templateDefinition2); return e; } if (eval instanceof EvalID) { @@ -349,16 +353,16 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { } ICPPTemplateArgument[] c2 = TemplateInstanceUtil.convert(this, c); - if (a != a2 || b != b2 || c != c2) - e= new EvalID(a2, b2, e.getName(), e.isAddressOf(), e.isQualified(), c2); + if (a != a2 || b != b2 || c != c2 || templateDefinition != templateDefinition2) + e= new EvalID(a2, b2, e.getName(), e.isAddressOf(), e.isQualified(), c2, templateDefinition2); return e; } if (eval instanceof EvalInitList) { EvalInitList e= (EvalInitList) eval; ICPPEvaluation[] a = e.getClauses(); ICPPEvaluation[] a2 = getCompositeEvaluationArray(a); - if (a != a2) - e= new EvalInitList(a2); + if (a != a2 || templateDefinition != templateDefinition2) + e= new EvalInitList(a2, templateDefinition2); return e; } if (eval instanceof EvalMemberAccess) { @@ -367,8 +371,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { IBinding b = e.getMember(); IType a2= getCompositeType(a); IBinding b2= getCompositeBinding((IIndexFragmentBinding) b); - if (a != a2 || b != b2) - e= new EvalMemberAccess(a2, e.getOwnerValueCategory(), b2, e.isPointerDeref()); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalMemberAccess(a2, e.getOwnerValueCategory(), b2, e.isPointerDeref(), templateDefinition2); return e; } if (eval instanceof EvalTypeId) { @@ -377,8 +381,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPEvaluation[] b = e.getArguments(); IType a2= getCompositeType(a); ICPPEvaluation[] b2 = getCompositeEvaluationArray(b); - if (a != a2 || b != b2) - e= new EvalTypeId(a2, b2); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalTypeId(a2, templateDefinition2, b2); return e; } if (eval instanceof EvalUnary) { @@ -387,16 +391,16 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPEvaluation a2 = getCompositeEvaluation(a); IBinding b= e.getAddressOfQualifiedNameBinding(); IBinding b2= getCompositeBinding((IIndexFragmentBinding) b); - if (a != a2 || b != b2) - e= new EvalUnary(e.getOperator(), a2, b2); + if (a != a2 || b != b2 || templateDefinition != templateDefinition2) + e= new EvalUnary(e.getOperator(), a2, b2, templateDefinition2); return e; } if (eval instanceof EvalUnaryTypeID) { EvalUnaryTypeID e= (EvalUnaryTypeID) eval; IType a = e.getArgument(); IType a2 = getCompositeType(a); - if (a != a2) - e= new EvalUnaryTypeID(e.getOperator(), a2); + if (a != a2 || templateDefinition != templateDefinition2) + e= new EvalUnaryTypeID(e.getOperator(), a2, templateDefinition2); return e; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index c24e8d698af..387ee12009b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -232,11 +232,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 139.0 - More efficient and robust storage of types and template arguments, bug 395243. * 140.0 - Enumerators with dependent values, bug 389009. * 140.1 - Mechanism for tagging nodes with extended data, bug TODO + * 141.0 - Storing enclosing template bindings for evaluations, bug 399829 */ - - private static final int MIN_SUPPORTED_VERSION= version(140, 0); - private static final int MAX_SUPPORTED_VERSION= version(140, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(140, 1); + private static final int MIN_SUPPORTED_VERSION= version(141, 0); + private static final int MAX_SUPPORTED_VERSION= version(141, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(141, 0); private static int version(int major, int minor) { return (major << 16) + minor; From ee08bee24b2ac0013f876fcb64ef6cebd8e35f4d Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Tue, 19 Feb 2013 00:01:33 -0500 Subject: [PATCH 08/11] Bug 401140 - NullPointerException in CPPTemplates.addDefaultArguments() Change-Id: I05fa8a3935904cb1bd293348dcbf10810e677b5c Reviewed-on: https://git.eclipse.org/r/10466 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../parser/tests/ast2/AST2TemplateTests.java | 22 +++++++++++++++++++ .../parser/cpp/semantics/CPPTemplates.java | 2 ++ 2 files changed, 24 insertions(+) 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 5b5b5fefb4e..81fee25b8cd 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 @@ -7271,4 +7271,26 @@ public class AST2TemplateTests extends AST2TestBase { public void testRegression_399829() throws Exception { parseAndCheckBindings(); } + + // template + // struct Bind {}; + // template + // struct Bind_helper { + // typedef Bind type; + // }; + // template + // typename Bind_helper::type + // bind(Func, BoundArgs...); + // struct S { + // template + // void operator()(T, U); + // }; + // int main() { + // S s; + // bind(s, 0, foo); + // } + public void testNPE_401140() throws Exception { + BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); + helper.assertProblem("bind(s, 0, foo)", "bind"); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 0069e6758bf..c1ad1d00893 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -1103,6 +1103,7 @@ public class CPPTemplates { ICPPTemplateArgument origArg = args[i]; ICPPTemplateArgument newArg; if (origArg.isPackExpansion()) { + ICPPTemplateArgument unexpanded= origArg; origArg= origArg.getExpansionPattern(); int packSize= determinePackSize(origArg, tpMap); if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) { @@ -1118,6 +1119,7 @@ public class CPPTemplates { if (!isValidArgument(newArg)) { if (strict) return null; + result[i + resultShift] = unexpanded; newResult = result; shift = 0; break; From 24ba7ff6880c98cab8a77144dc1c8f08c8d8db9c Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Tue, 19 Feb 2013 03:27:53 -0500 Subject: [PATCH 09/11] Bug 401142 - Error involving variadic non-type template parameters Change-Id: I7735649c59354431a91980142055e4b86a82e6f6 Reviewed-on: https://git.eclipse.org/r/10467 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../parser/tests/ast2/AST2TemplateTests.java | 19 +++++++++++++++++++ .../parser/cpp/semantics/CPPTemplates.java | 2 ++ 2 files changed, 21 insertions(+) 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 81fee25b8cd..57a89c6ff7b 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 @@ -7292,5 +7292,24 @@ public class AST2TemplateTests extends AST2TestBase { public void testNPE_401140() throws Exception { BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); helper.assertProblem("bind(s, 0, foo)", "bind"); + } + + // template + // struct ice_or; + // template + // struct ice_or { + // static const bool value = First; + // }; + // template + // struct S {}; + // template <> + // struct S { + // typedef int type; + // }; + // int main() { + // S::value>::type t; + // } + public void testVariadicNonTypeTemplateParameter_401142() throws Exception { + parseAndCheckBindings(); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index c1ad1d00893..4650cc7183f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -2464,6 +2464,8 @@ public class CPPTemplates { } else { if (arg.isTypeValue()) return false; + if (par.isParameterPack() != arg.isPackExpansion()) + return false; int parpos= Value.isTemplateParameter(arg.getNonTypeValue()); if (parpos != par.getParameterID()) return false; From 1908efec3811e8c24030a5b38140b00fbb66ca61 Mon Sep 17 00:00:00 2001 From: Andrew Eidsness Date: Wed, 20 Feb 2013 13:23:40 -0500 Subject: [PATCH 10/11] qt slot/signal auto-complete Tags signal and slot methods when the index is created. Uses these tags to suggest values inside of SIGNAL and SLOT macro expansions. Enabled only for projects with the QtNature. Recognizes QObject::connect function calls and suggests SIGNAL(a) and SLOT(a) for the 2nd and 4th parameters. When expanding the SIGNAL and SLOT macros within a call to QObject::connect, suggests signals and slots based on the type of the previous parameter. E.g. in QObjectA a; QObjectB b; QObject::connect( &a, SIGNAL(*), &b, SLOT(**) ); The content assistant will suggest the methods of type QObjectA that have been marked as signals at *, and the methods of QObjectB that have been marked as slots at **. Change-Id: Ia6aaa71724547b0977e322399a500f072004767a Reviewed-on: https://git.eclipse.org/r/10532 Reviewed-by: Doug Schaefer IP-Clean: Doug Schaefer Tested-by: Doug Schaefer --- .../META-INF/MANIFEST.MF | 2 +- qt/org.eclipse.cdt.qt.core/plugin.xml | 16 + .../org/eclipse/cdt/qt/core/Activator.java | 30 -- .../org/eclipse/cdt/qt/core/QtKeywords.java | 6 + .../src/org/eclipse/cdt/qt/core/QtPlugin.java | 38 ++ .../qt/internal/core/QtSignalSlotTagger.java | 101 +++++ qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF | 6 +- qt/org.eclipse.cdt.qt.ui/plugin.xml | 12 + .../ui/QtCompletionProposalComputer.java | 392 ++++++++++++++++++ .../qt/ui/{Activator.java => QtUIPlugin.java} | 8 +- 10 files changed, 574 insertions(+), 37 deletions(-) delete mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java create mode 100644 qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java rename qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/{Activator.java => QtUIPlugin.java} (85%) diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF index 67bb08fb6ca..31d4aeefd56 100644 --- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: CDT Qt Support Core Bundle-SymbolicName: org.eclipse.cdt.qt.core;singleton:=true Bundle-Version: 1.0.0.qualifier -Bundle-Activator: org.eclipse.cdt.qt.core.Activator +Bundle-Activator: org.eclipse.cdt.qt.core.QtPlugin Bundle-Vendor: Eclipse CDT Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources, diff --git a/qt/org.eclipse.cdt.qt.core/plugin.xml b/qt/org.eclipse.cdt.qt.core/plugin.xml index 959e78450a5..d31e961af1d 100644 --- a/qt/org.eclipse.cdt.qt.core/plugin.xml +++ b/qt/org.eclipse.cdt.qt.core/plugin.xml @@ -50,4 +50,20 @@ + + + + + + + + + + + diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java deleted file mode 100644 index 2e3a4ecd3a4..00000000000 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/Activator.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.eclipse.cdt.qt.core; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class Activator implements BundleActivator { - - private static BundleContext context; - - static BundleContext getContext() { - return context; - } - - /* - * (non-Javadoc) - * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext bundleContext) throws Exception { - Activator.context = bundleContext; - } - - /* - * (non-Javadoc) - * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext bundleContext) throws Exception { - Activator.context = null; - } - -} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java index 36b2112585d..381655ef025 100644 --- a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtKeywords.java @@ -17,4 +17,10 @@ public class QtKeywords public static final String Q_SLOTS = "Q_SLOTS"; public static final String SIGNALS = "signals"; public static final String SLOTS = "slots"; + + public static final String SIGNAL = "SIGNAL"; + public static final String SLOT = "SLOT"; + + public static final String QOBJECT = "QObject"; + public static final String CONNECT = "connect"; } diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java new file mode 100644 index 00000000000..825b5614cc7 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/QtPlugin.java @@ -0,0 +1,38 @@ +package org.eclipse.cdt.qt.core; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class QtPlugin implements BundleActivator { + + public static final String ID = "org.eclipse.cdt.qt.core"; + public static final String SIGNAL_SLOT_TAGGER_ID = ID + ".signalslot.tagger"; + + public static final int SignalSlot_Mask_signal = 1; + public static final int SignalSlot_Mask_slot = 2; + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + QtPlugin.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + QtPlugin.context = null; + } + +} diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java new file mode 100644 index 00000000000..a82b3c15547 --- /dev/null +++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/internal/core/QtSignalSlotTagger.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.qt.internal.core; + +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.tag.IBindingTagger; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagWriter; +import org.eclipse.cdt.core.dom.ast.tag.IWritableTag; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.QtPlugin; + +public class QtSignalSlotTagger implements IBindingTagger +{ + private static ICPPASTVisibilityLabel findVisibilityLabel( ICPPMethod method, IASTNode ast ) + { + // the visibility cannot be found without an ast + if( ast == null ) + return null; + + IASTNode methodDecl = ast; + ICPPASTCompositeTypeSpecifier classType = null; + while( methodDecl != null + && classType == null ) + { + IASTNode parent = methodDecl.getParent(); + if( parent instanceof ICPPASTCompositeTypeSpecifier ) + classType = (ICPPASTCompositeTypeSpecifier)parent; + else + methodDecl = parent; + } + + if( methodDecl == null + || classType == null ) + return null; + + ICPPASTVisibilityLabel lastLabel = null; + for( IASTDeclaration decl : classType.getMembers() ) + { + if( decl instanceof ICPPASTVisibilityLabel ) + lastLabel = (ICPPASTVisibilityLabel)decl; + else if( decl == methodDecl ) + return lastLabel; + } + + return null; + } + + @Override + public ITag process( ITagWriter tagWriter, IBinding binding, IASTName ast ) + { + // only methods a be signals or slots + if( ! ( binding instanceof ICPPMethod ) ) + return null; + + // a visibility label is required in order to decide whether the method is a signal/slot + ICPPMethod method = (ICPPMethod)binding; + ICPPASTVisibilityLabel v = findVisibilityLabel( method, ast ); + if( v == null ) + return null; + + byte bitset = 0; + for( IASTNodeLocation loc : v.getNodeLocations() ) + if( loc instanceof IASTMacroExpansionLocation ) + { + IASTMacroExpansionLocation macroExpansion = (IASTMacroExpansionLocation)loc; + IASTPreprocessorMacroExpansion exp = macroExpansion.getExpansion(); + String macro = exp.getMacroReference().toString(); + + if( QtKeywords.SIGNALS.equals( macro ) || QtKeywords.Q_SIGNALS.equals( macro ) ) + bitset |= QtPlugin.SignalSlot_Mask_signal; + else if( QtKeywords.SLOTS.equals( macro ) || QtKeywords.Q_SLOTS.equals( macro ) ) + bitset |= QtPlugin.SignalSlot_Mask_slot; + } + + if( bitset != 0 ) + { + IWritableTag tag = tagWriter.createTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID, 1 ); + if( tag != null + && tag.putByte( 0, bitset ) ) + return tag; + } + + return null; + } +} diff --git a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF index 0e024d23ae1..856b83c6f2a 100644 --- a/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF +++ b/qt/org.eclipse.cdt.qt.ui/META-INF/MANIFEST.MF @@ -3,13 +3,15 @@ Bundle-ManifestVersion: 2 Bundle-Name: CDT Qt Support UI Bundle-SymbolicName: org.eclipse.cdt.qt.ui;singleton:=true Bundle-Version: 1.0.0.qualifier -Bundle-Activator: org.eclipse.cdt.qt.ui.Activator +Bundle-Activator: org.eclipse.cdt.qt.ui.QtUIPlugin Bundle-Vendor: Eclipse CDT Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.cdt.ui, org.eclipse.cdt.core, - org.eclipse.cdt.qt.core + org.eclipse.cdt.qt.core, + org.eclipse.jface.text, + org.eclipse.core.resources Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy diff --git a/qt/org.eclipse.cdt.qt.ui/plugin.xml b/qt/org.eclipse.cdt.qt.ui/plugin.xml index 7d86d31f7c4..e03dd26e7ab 100644 --- a/qt/org.eclipse.cdt.qt.ui/plugin.xml +++ b/qt/org.eclipse.cdt.qt.ui/plugin.xml @@ -23,4 +23,16 @@ + + + + + + diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java new file mode 100644 index 00000000000..733e08857ab --- /dev/null +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/internal/ui/QtCompletionProposalComputer.java @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2013 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.eclipse.cdt.qt.internal.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; +import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; +import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.tag.ITag; +import org.eclipse.cdt.core.dom.ast.tag.ITagReader; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; +import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal; +import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistInvocationContext; +import org.eclipse.cdt.internal.ui.text.contentassist.ParsingBasedProposalComputer; +import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants; +import org.eclipse.cdt.qt.core.QtKeywords; +import org.eclipse.cdt.qt.core.QtNature; +import org.eclipse.cdt.qt.core.QtPlugin; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.contentassist.ICompletionProposal; + +@SuppressWarnings( "restriction" ) +public class QtCompletionProposalComputer extends ParsingBasedProposalComputer +{ + private boolean isApplicable( CContentAssistInvocationContext context ) + { + ITranslationUnit tu = context.getTranslationUnit(); + if( tu == null ) + return false; + + ICProject cProject = tu.getCProject(); + if( cProject == null ) + return false; + + IProject project = cProject.getProject(); + if( project == null ) + return false; + + try + { + return project.hasNature( QtNature.ID ); + } + catch( CoreException e ) + { + CUIPlugin.log( e ); + return false; + } + } + + private static boolean is_QObject_connect( CContentAssistInvocationContext context, IASTCompletionContext astContext, IASTName name ) + { + IASTName connectName = name.getLastName(); + if( ! QtKeywords.CONNECT.equals( new String( connectName.getSimpleID() ) ) ) + return false; + + IBinding[] funcBindings = astContext.findBindings( connectName, ! context.isContextInformationStyle() ); + for( IBinding funcBinding : funcBindings ) + if( funcBinding instanceof ICPPFunction ) + { + IBinding ownerBinding = ( (ICPPFunction)funcBinding ).getOwner(); + if( ownerBinding != null && QtKeywords.QOBJECT.equals( ownerBinding.getName() ) ) + return true; + } + + return false; + } + + private static class Completion + { + private final String replacement; + private final String display; + private final int cursorOffset; + + public static final Completion SIGNAL = new Completion( "SIGNAL()", "SIGNAL(a)", -1 ); + public static final Completion SLOT = new Completion( "SLOT()", "SLOT(a)", -1 ); + + public Completion( String replacement ) + { + this( replacement, replacement, 0 ); + } + + public Completion( String replacement, String display, int cursorOffset ) + { + this.replacement = replacement; + this.display = display; + this.cursorOffset = cursorOffset; + } + + public ICompletionProposal createProposal( CContentAssistInvocationContext context ) + { + int repLength = replacement.length(); + int repOffset = context.getInvocationOffset(); + CCompletionProposal p = new CCompletionProposal( replacement, repOffset, repLength, null, display, RelevanceConstants.DEFAULT_TYPE_RELEVANCE, context.getViewer() ); + p.setCursorPosition( repLength + cursorOffset ); + return p; + } + + @Override + public String toString() + { + if( replacement == null ) + return super.toString(); + return replacement + '@' + cursorOffset; + } + } + + private static interface MethodFilter + { + public boolean keep( ICPPMethod method ); + + public static class Qt + { + public static final MethodFilter Signal = new MethodFilter() + { + @Override + public boolean keep( ICPPMethod method ) + { + ITagReader tagReader = CCorePlugin.getTagService().findTagReader( method ); + if( tagReader == null ) + return false; + + ITag tag = tagReader.getTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID ); + if( tag == null ) + return false; + + int result = tag.getByte( 0 ); + return result != ITag.Fail + && ( ( result & QtPlugin.SignalSlot_Mask_signal ) == QtPlugin.SignalSlot_Mask_signal ); + } + }; + + public static final MethodFilter Slot = new MethodFilter() + { + @Override + public boolean keep( ICPPMethod method ) + { + ITagReader tagReader = CCorePlugin.getTagService().findTagReader( method ); + if( tagReader == null ) + return false; + + ITag tag = tagReader.getTag( QtPlugin.SIGNAL_SLOT_TAGGER_ID ); + if( tag == null ) + return false; + + int result = tag.getByte( 0 ); + return result != ITag.Fail + && ( ( result & QtPlugin.SignalSlot_Mask_slot ) == QtPlugin.SignalSlot_Mask_slot ); + } + }; + } + } + + private static Iterable filterMethods( final ICPPClassType cls, final MethodFilter filter ) + { + return new Iterable() + { + @Override + public Iterator iterator() + { + return new Iterator() + { + private int index = 0; + private final ICPPMethod[] methods = cls.getMethods(); + + @Override + public boolean hasNext() + { + for( ; index < methods.length; ++index ) + if( filter.keep( methods[index] ) ) + return true; + return false; + } + + @Override public ICPPMethod next() { return methods[index++]; } + @Override public void remove() { } + }; + } + }; + } + + private static String getSignature( ICPPMethod method ) + { + StringBuilder signature = new StringBuilder(); + + signature.append( method.getName() ); + signature.append( '(' ); + boolean first = true; + for( ICPPParameter param : method.getParameters() ) + { + if( first ) + first = false; + else + signature.append( ", " ); + signature.append( ASTTypeUtil.getType( param.getType() ) ); + } + + signature.append( ')' ); + return signature.toString(); + } + + private static void addCompletionsFor( Collection completions, IASTInitializerClause init, MethodFilter filter ) + { + if( !( init instanceof ICPPASTInitializerClause ) ) + return; + + ICPPEvaluation eval = ( (ICPPASTInitializerClause)init ).getEvaluation(); + if( eval == null ) + return; + + IType type = eval.getTypeOrFunctionSet( init ); + while( type instanceof IPointerType ) + type = ( (IPointerType)type ).getType(); + + if( type instanceof ICPPClassType ) + for( ICPPMethod signal : filterMethods( (ICPPClassType)type, filter ) ) + completions.add( new Completion( getSignature( signal ) ) ); + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int indexOfClosingPeer(String code, char left, char right, int pos) { + int level= 0; + final int length= code.length(); + while (pos < length) { + char ch= code.charAt(pos); + if (ch == left) { + ++level; + } else if (ch == right) { + if (--level == 0) { + return pos; + } + } + ++pos; + } + return -1; + } + + // Copied from org.eclipse.cdt.internal.ui.text.CParameterListValidator + private static int[] computeCommaPositions(String code) { + final int length= code.length(); + int pos= 0; + List positions= new ArrayList(); + positions.add(new Integer(-1)); + while (pos < length && pos != -1) { + char ch= code.charAt(pos); + switch (ch) { + case ',': + positions.add(new Integer(pos)); + break; + case '(': + pos= indexOfClosingPeer(code, '(', ')', pos); + break; + case '<': + pos= indexOfClosingPeer(code, '<', '>', pos); + break; + case '[': + pos= indexOfClosingPeer(code, '[', ']', pos); + break; + default: + break; + } + if (pos != -1) + pos++; + } + positions.add(new Integer(length)); + + int[] fields= new int[positions.size()]; + for (int i= 0; i < fields.length; i++) + fields[i]= positions.get(i).intValue(); + return fields; + } + + + private void addConnectParameterCompletions( List proposals, CContentAssistInvocationContext context, IASTCompletionNode completionNode, String prefix ) + { + IASTName[] names = completionNode.getNames(); + List completions = new LinkedList(); + + for( IASTName name : names ) + { + // The node isn't properly hooked up, must have backtracked out of this node + if( name.getTranslationUnit() == null ) + continue; + + IASTCompletionContext astContext = name.getCompletionContext(); + if( astContext == null || ! ( astContext instanceof IASTNode ) ) + continue; + IASTNode astNode = (IASTNode)astContext; + + if( is_QObject_connect( context, astContext, name ) ) + { + int parseOffset = context.getParseOffset(); + int invocationOffset = context.getInvocationOffset(); + + String unparsed = ""; + try { unparsed = context.getDocument().get( parseOffset, invocationOffset - parseOffset ); } + catch( BadLocationException e ) { CCorePlugin.log( e ); } + + if( unparsed.length() > 0 && unparsed.charAt( 0 ) == '(' ) + unparsed = unparsed.substring( 1 ); + + int[] commas = computeCommaPositions( unparsed ); + switch( commas.length ) + { + case 3: + completions.add( Completion.SIGNAL ); + break; + case 5: + completions.add( Completion.SLOT ); + break; + } + } + else if( astNode.getPropertyInParent() == IASTFunctionCallExpression.ARGUMENT ) + { + IASTNode parent = astNode.getParent(); + if( ! ( parent instanceof IASTFunctionCallExpression ) ) + continue; + IASTFunctionCallExpression call = (IASTFunctionCallExpression)parent; + IASTExpression nameExpr = call.getFunctionNameExpression(); + if( !( nameExpr instanceof IASTIdExpression ) ) + continue; + IASTIdExpression funcNameIdExpr = (IASTIdExpression)nameExpr; + IASTName funcName = funcNameIdExpr.getName(); + + if( !is_QObject_connect( context, astContext, funcName ) ) + continue; + + IASTInitializerClause[] args = call.getArguments(); + switch( args.length ) + { + case 2: + //if( QtKeywords.SIGNAL.equals( prefix ) ) + addCompletionsFor( completions, args[0], MethodFilter.Qt.Signal ); + break; + case 4: + if( QtKeywords.SLOT.equals( prefix ) ) + addCompletionsFor( completions, args[2], MethodFilter.Qt.Slot ); + break; + } + } + } + + for( Completion completion : completions ) + { + ICompletionProposal proposal = completion.createProposal( context ); + if( proposal != null ) + proposals.add( proposal ); + } + } + + @Override + protected List computeCompletionProposals( CContentAssistInvocationContext context, IASTCompletionNode completionNode, String prefix ) throws CoreException + { + if( !isApplicable( context ) ) + return Collections.emptyList(); + + List proposals = new ArrayList(); + addConnectParameterCompletions( proposals, context, completionNode, prefix ); + return proposals; + } +} diff --git a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java similarity index 85% rename from qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java rename to qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java index 5d1039b2ae0..d4b781e9e8b 100644 --- a/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/Activator.java +++ b/qt/org.eclipse.cdt.qt.ui/src/org/eclipse/cdt/qt/ui/QtUIPlugin.java @@ -6,18 +6,18 @@ import org.osgi.framework.BundleContext; /** * The activator class controls the plug-in life cycle */ -public class Activator extends AbstractUIPlugin { +public class QtUIPlugin extends AbstractUIPlugin { // The plug-in ID public static final String PLUGIN_ID = "org.eclipse.cdt.qt.ui"; //$NON-NLS-1$ // The shared instance - private static Activator plugin; + private static QtUIPlugin plugin; /** * The constructor */ - public Activator() { + public QtUIPlugin() { } /* @@ -43,7 +43,7 @@ public class Activator extends AbstractUIPlugin { * * @return the shared instance */ - public static Activator getDefault() { + public static QtUIPlugin getDefault() { return plugin; } From 18ff30de24e745ca9f221c49ff8bd219837022c7 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Tue, 19 Feb 2013 18:22:07 -0500 Subject: [PATCH 11/11] Bug 400972: Creating new C/C++ project in existing read-only directory should be disallowed Change-Id: I75090498bd4f408d77ad17491f50f4fd66850c97 Reviewed-on: https://git.eclipse.org/r/10404 Reviewed-by: Jesse Weinstein Reviewed-by: Jeff Johnston IP-Clean: Jeff Johnston Tested-by: Jeff Johnston --- .../eclipse/cdt/managedbuilder/internal/ui/Messages.java | 1 + .../cdt/managedbuilder/internal/ui/Messages.properties | 2 ++ .../ui/wizards/NewMakeProjFromExistingPage.java | 5 ++++- .../src/org/eclipse/cdt/internal/ui/newui/Messages.java | 1 + .../org/eclipse/cdt/internal/ui/newui/Messages.properties | 1 + .../src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java | 7 ++++++- 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java index 69436a7ed94..18939f441d6 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.java @@ -186,6 +186,7 @@ public class Messages extends NLS { public static String NewMakeProjFromExistingPage_7; public static String NewMakeProjFromExistingPage_8; public static String NewMakeProjFromExistingPage_9; + public static String NewMakeProjFromExistingPage_DirReadOnlyError; public static String NewVarDialog_0; public static String NewVarDialog_1; public static String PreferredToolchainsTab_0; diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties index ac4acf5dce1..d45a0a1285a 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/internal/ui/Messages.properties @@ -152,6 +152,8 @@ NewMakeProjFromExistingPage_6=Browse... NewMakeProjFromExistingPage_7=Select root directory of existing code NewMakeProjFromExistingPage_8=Not a valid directory NewMakeProjFromExistingPage_9=Languages +NewMakeProjFromExistingPage_DirReadOnlyError=Directory is read-only + # ----------- Configuration Selection Page ----------- BuildPropertyPage_error_Unknown_tree_element=Unknown type of element in tree of type {0} diff --git a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java index 8848e47386a..b9f817f07bb 100644 --- a/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java +++ b/build/org.eclipse.cdt.managedbuilder.ui/src/org/eclipse/cdt/managedbuilder/ui/wizards/NewMakeProjFromExistingPage.java @@ -155,10 +155,13 @@ public class NewMakeProjFromExistingPage extends WizardPage { else { final File file= new File(loc); if (file.isDirectory()) { + // Ensure we can create files in the directory. + if (!file.canWrite()) + msg = Messages.NewMakeProjFromExistingPage_DirReadOnlyError; // Set the project name to the directory name but not if the user has supplied a name // (bugzilla 368987). Use a job to ensure proper sequence of activity, as setting the Text // will invoke the listener, which will invoke this method. - if (!projectNameSetByUser && !name.equals(file.getName())) { + else if (!projectNameSetByUser && !name.equals(file.getName())) { WorkbenchJob wjob = new WorkbenchJob("update project name") { //$NON-NLS-1$ @Override public IStatus runInUIThread(IProgressMonitor monitor) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java index 29c4a9f4a33..8748aa13afa 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.java @@ -105,6 +105,7 @@ public class Messages extends NLS { public static String CMainWizardPage_5; public static String CMainWizardPage_6; public static String CMainWizardPage_7; + public static String CMainWizardPage_DirReadOnlyError; public static String ConfigDescriptionTab_0; public static String ConfigDescriptionTab_1; public static String ConfigDescriptionTab_2; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties index fb82cc455f3..839d769eab1 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/newui/Messages.properties @@ -273,6 +273,7 @@ CMainWizardPage_3=No project types available. Project cannot be created CMainWizardPage_5=Cannot create ICProjectTypeHandler: CMainWizardPage_6=File with specified name already exists. CMainWizardPage_7=Directory with specified name already exists. +CMainWizardPage_DirReadOnlyError=Directory with specified name already exists and is read-only. ProjectContentsArea_0=Browse... ProjectContentsArea_1=Use default location diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java index d8b09411ef6..133785d1776 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/CDTMainWizardPage.java @@ -211,7 +211,12 @@ import org.eclipse.cdt.internal.ui.newui.Messages; IFileInfo f = fs.fetchInfo(); if (f.exists()) { if (f.isDirectory()) { - setMessage(Messages.CMainWizardPage_7, IMessageProvider.WARNING); + if (f.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) { + setErrorMessage(Messages.CMainWizardPage_DirReadOnlyError); + return false; + } + else + setMessage(Messages.CMainWizardPage_7, IMessageProvider.WARNING); } else { setErrorMessage(Messages.CMainWizardPage_6); return false;