mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Merge remote-tracking branch 'cdt/master' into sd90
This commit is contained in:
commit
0df3dfbbbc
55 changed files with 2627 additions and 679 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2010 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2011 IBM Corporation 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
|
||||
|
@ -58,7 +58,6 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider {
|
|||
private static final String EXTERNAL_SI_PROVIDER_ERROR = "ExternalScannerInfoProvider.Provider_Error"; //$NON-NLS-1$
|
||||
private static final String GMAKE_ERROR_PARSER_ID = "org.eclipse.cdt.core.GmakeErrorParser"; //$NON-NLS-1$
|
||||
private static final String PREF_CONSOLE_ENABLED = "org.eclipse.cdt.make.core.scanner.discovery.console.enabled"; //$NON-NLS-1$
|
||||
private static final String LANG_ENV_VAR = "LANG"; //$NON-NLS-1$
|
||||
private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
private static final String PATH_ENV = "PATH"; //$NON-NLS-1$
|
||||
|
||||
|
@ -269,14 +268,12 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider {
|
|||
props.put("PWD", fWorkingDirectory.toOSString()); //$NON-NLS-1$
|
||||
}
|
||||
// On POSIX (Linux, UNIX) systems reset LANG variable to English with
|
||||
// UTF-8 encoding
|
||||
// since GNU compilers can handle only UTF-8 characters. English language is chosen
|
||||
// beacuse GNU compilers inconsistently handle different locales when generating
|
||||
// output of the 'gcc -v' command. Include paths with locale characters will be
|
||||
// handled properly regardless of the language as long as the encoding is set to UTF-8.
|
||||
if (props.containsKey(LANG_ENV_VAR)) {
|
||||
props.put(LANG_ENV_VAR, "en_US.UTF-8"); //$NON-NLS-1$
|
||||
}
|
||||
// UTF-8 encoding since GNU compilers can handle only UTF-8 characters.
|
||||
// Include paths with locale characters will be handled properly regardless
|
||||
// of the language as long as the encoding is set to UTF-8.
|
||||
// English language is chosen because parser relies on English messages
|
||||
// in the output of the 'gcc -v' command.
|
||||
props.put("LC_ALL", "en_US.UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return props;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2010 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2011 IBM Corporation 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
|
||||
|
@ -26,7 +26,6 @@ import org.eclipse.core.runtime.CoreException;
|
|||
* @author vhirsl
|
||||
*/
|
||||
public class GCCSpecsRunSIProvider extends DefaultRunSIProvider {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#initialize()
|
||||
*/
|
||||
|
|
|
@ -338,9 +338,9 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
|
|||
|
||||
if (parentConfig != null) {
|
||||
name = parentConfig.getName();
|
||||
// If this contructor is called to clone an existing
|
||||
// If this constructor is called to clone an existing
|
||||
// configuration, the parent of the parent should be stored.
|
||||
// As of 2.1, there is still one single level of inheritence to
|
||||
// As of 2.1, there is still one single level of inheritance to
|
||||
// worry about
|
||||
parent = parentConfig.getParent() == null ? parentConfig : parentConfig.getParent();
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
|
|||
|
||||
// if(!baseCfg.isExtensionConfig)
|
||||
// cloneChildren = true;
|
||||
// If this contructor is called to clone an existing
|
||||
// If this constructor is called to clone an existing
|
||||
// configuration, the parent of the cloning config should be stored.
|
||||
parent = baseCfg.isExtensionConfig || baseCfg.getParent() == null ? baseCfg : baseCfg.getParent();
|
||||
|
||||
|
@ -634,7 +634,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
|
|||
|
||||
if(!cloneConfig.isExtensionConfig)
|
||||
cloneChildren = true;
|
||||
// If this contructor is called to clone an existing
|
||||
// If this constructor is called to clone an existing
|
||||
// configuration, the parent of the cloning config should be stored.
|
||||
parent = cloneConfig.isExtensionConfig || cloneConfig.getParent() == null ? cloneConfig : cloneConfig.getParent();
|
||||
parentId = parent.getId();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2010 Intel Corporation and others.
|
||||
* Copyright (c) 2005, 2011 Intel Corporation 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
|
||||
|
@ -23,10 +23,15 @@ import org.eclipse.cdt.managedbuilder.internal.envvar.BuildEnvVar;
|
|||
public class GnuCygwinConfigurationEnvironmentSupplier implements
|
||||
IConfigurationEnvironmentVariableSupplier {
|
||||
|
||||
static final String VARNAME = "PATH"; //$NON-NLS-1$
|
||||
static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$
|
||||
static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$
|
||||
static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$
|
||||
private static final String PATH = "PATH"; //$NON-NLS-1$
|
||||
private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$
|
||||
private static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$
|
||||
private static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$
|
||||
|
||||
private static final String LANG = "LANG"; //$NON-NLS-1$
|
||||
private static final String LC_ALL = "LC_ALL"; //$NON-NLS-1$
|
||||
private static final String LC_MESSAGES = "LC_MESSAGES"; //$NON-NLS-1$
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier#getVariable(java.lang.String, org.eclipse.cdt.managedbuilder.core.IConfiguration, org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider)
|
||||
*/
|
||||
|
@ -34,15 +39,33 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements
|
|||
public IBuildEnvironmentVariable getVariable(String variableName,
|
||||
IConfiguration configuration, IEnvironmentVariableProvider provider) {
|
||||
|
||||
if (variableName == null)
|
||||
return null;
|
||||
|
||||
if (!System.getProperty(PROPERTY_OSNAME).toLowerCase().startsWith("windows ")) //$NON-NLS-1$
|
||||
return null;
|
||||
|
||||
if (variableName == null) return null;
|
||||
if (!VARNAME.equalsIgnoreCase(variableName)) return null;
|
||||
|
||||
if (variableName.equalsIgnoreCase(PATH)) {
|
||||
String p = CygwinPathResolver.getBinPath();
|
||||
if (p != null)
|
||||
return new BuildEnvVar(VARNAME, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX));
|
||||
return new BuildEnvVar(PATH, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX));
|
||||
} else if (variableName.equalsIgnoreCase(LANG)) {
|
||||
// Workaround for not being able to select encoding for CDT console -> change codeset to Latin1
|
||||
String langValue = System.getenv(LANG);
|
||||
if (langValue == null || langValue.length() == 0)
|
||||
langValue = System.getenv(LC_ALL);
|
||||
if (langValue == null || langValue.length() == 0)
|
||||
langValue = System.getenv(LC_MESSAGES);
|
||||
if (langValue != null && langValue.length() > 0)
|
||||
// langValue is [language[_territory][.codeset][@modifier]], i.e. "en_US.UTF-8@dict"
|
||||
// we replace codeset with Latin1 as CDT console garbles UTF
|
||||
// and ignore modifier which is not used by LANG
|
||||
langValue = langValue.replaceFirst("([^.@]*)(\\..*)?(@.*)?", "$1.ISO-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
else
|
||||
langValue = "C.ISO-8859-1"; //$NON-NLS-1$
|
||||
|
||||
return new BuildEnvVar(LANG, langValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -53,9 +76,13 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements
|
|||
public IBuildEnvironmentVariable[] getVariables(
|
||||
IConfiguration configuration, IEnvironmentVariableProvider provider) {
|
||||
|
||||
IBuildEnvironmentVariable[] tmp = new IBuildEnvironmentVariable[1];
|
||||
tmp[0] = getVariable(VARNAME, configuration, provider);
|
||||
if (tmp[0] != null) return tmp;
|
||||
return null;
|
||||
IBuildEnvironmentVariable varLang = getVariable(LANG, configuration, provider);
|
||||
IBuildEnvironmentVariable varPath = getVariable(PATH, configuration, provider);
|
||||
|
||||
if (varPath != null) {
|
||||
return new IBuildEnvironmentVariable[] {varLang, varPath};
|
||||
} else {
|
||||
return new IBuildEnvironmentVariable[] {varLang};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
|
|||
|
||||
public int visit(IASTExpression expression) {
|
||||
if (!constructorsStack.empty() && expression instanceof IASTFunctionCallExpression) {
|
||||
Set<IField> actualContructorFields = constructorsStack.peek();
|
||||
if (!actualContructorFields.isEmpty()) {
|
||||
Set<IField> actualConstructorFields = constructorsStack.peek();
|
||||
if (!actualConstructorFields.isEmpty()) {
|
||||
boolean skipCurrentConstructor = false;
|
||||
IASTFunctionCallExpression fCall = (IASTFunctionCallExpression)expression;
|
||||
IASTExpression fNameExp = fCall.getFunctionNameExpression();
|
||||
|
@ -108,7 +108,7 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
|
|||
IBinding fBinding = fName.getName().resolveBinding();
|
||||
if (fBinding instanceof ICPPMethod) {
|
||||
ICPPMethod method = (ICPPMethod)fBinding;
|
||||
ICompositeType constructorOwner = actualContructorFields.iterator().next().getCompositeTypeOwner();
|
||||
ICompositeType constructorOwner = actualConstructorFields.iterator().next().getCompositeTypeOwner();
|
||||
if (constructorOwner == method.getClassOwner() && !method.getType().isConst()) {
|
||||
skipCurrentConstructor = true;
|
||||
}
|
||||
|
@ -152,12 +152,12 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
|
|||
|
||||
public int visit(IASTName name) {
|
||||
if (!constructorsStack.empty()) {
|
||||
Set<IField> actualContructorFields = constructorsStack.peek();
|
||||
if (!actualContructorFields.isEmpty()) {
|
||||
Set<IField> actualConstructorFields = constructorsStack.peek();
|
||||
if (!actualConstructorFields.isEmpty()) {
|
||||
IBinding binding = name.resolveBinding();
|
||||
if (actualContructorFields.contains(binding)) {
|
||||
if (actualConstructorFields.contains(binding)) {
|
||||
if ((CPPVariableReadWriteFlags.getReadWriteFlags(name) & PDOMName.WRITE_ACCESS) != 0) {
|
||||
actualContructorFields.remove(binding);
|
||||
actualConstructorFields.remove(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
|
|||
// int m;
|
||||
// C() { m = 0; } // No warnings.
|
||||
// };
|
||||
public void testAssignmentsInContructorShouldBeChecked() {
|
||||
public void testAssignmentsInConstructorShouldBeChecked() {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrors();
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
|
|||
// int i1, i2;
|
||||
// };
|
||||
// C::C() : i1(0) {} // 1 warning for: i2.
|
||||
public void testExternalContructorHandling() {
|
||||
public void testExternalConstructorHandling() {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLines(5);
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
|
|||
// T2 t2;
|
||||
// };
|
||||
// C::C() : i1(0), t1(T1()) {} // 1 warning for: i2.
|
||||
public void testExternalContructorOfTemplateClassHandling() {
|
||||
public void testExternalConstructorOfTemplateClassHandling() {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLines(8);
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
|
|||
// };
|
||||
// template <typename T>
|
||||
// C::C() : i1(0) {} // 1 warning for: i2.
|
||||
public void testExternalTemplateContructorHandling() {
|
||||
public void testExternalTemplateConstructorHandling() {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLines(7);
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
|
|||
// template <typename T1, typename T2>
|
||||
// template <typename T>
|
||||
// C<T1,T2>::C() : i1(0), t1(T1()) {} // 1 warning for: i2.
|
||||
public void testExternalTemplateContructorOfTemplateClassHandling() {
|
||||
public void testExternalTemplateConstructorOfTemplateClassHandling() {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLines(11);
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ public class ReturnCheckerTest extends CheckerTestCase {
|
|||
// return;
|
||||
// }
|
||||
// };
|
||||
public void testContructorRetValue() {
|
||||
public void testConstructorRetValue() {
|
||||
loadCodeAndRunCpp(getAboveComment());
|
||||
checkErrorLine(3, ReturnChecker.RET_ERR_VALUE_ID);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class ReturnCheckerTest extends CheckerTestCase {
|
|||
// return;
|
||||
// }
|
||||
// };
|
||||
public void testContructor_Bug323602() {
|
||||
public void testConstructor_Bug323602() {
|
||||
IProblemPreference macro = getPreference(ReturnChecker.RET_NO_VALUE_ID, ReturnChecker.PARAM_IMPLICIT);
|
||||
macro.setValue(Boolean.TRUE);
|
||||
loadCodeAndRunCpp(getAboveComment());
|
||||
|
|
|
@ -86,7 +86,7 @@ ptym_open(char * pts_name)
|
|||
char *ptr;
|
||||
|
||||
strcpy(pts_name, "/dev/ptmx");
|
||||
fdm = getpt();
|
||||
fdm = posix_openpt(O_RDWR);
|
||||
if (fdm < 0)
|
||||
return -1;
|
||||
if (grantpt(fdm) < 0) { /* grant access to slave */
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1942,16 +1942,17 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
|
|||
}
|
||||
|
||||
// void f(double& a) { a += 3.14; }
|
||||
// // ...
|
||||
// int foo() {
|
||||
// void foo1() {
|
||||
// double d = 0;
|
||||
// f(d);
|
||||
// }
|
||||
//
|
||||
// int v[20];
|
||||
// // ...
|
||||
// int& g(int i) { return v[i]; }
|
||||
// // ...
|
||||
// void foo2() {
|
||||
// g(3) = 7;
|
||||
// }
|
||||
//
|
||||
// struct link {
|
||||
// link* next;
|
||||
// };
|
||||
|
@ -1967,7 +1968,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
|
|||
// link* q = new link;
|
||||
// h(q);
|
||||
// }
|
||||
public void test8_3_2s2() throws Exception {
|
||||
public void test8_3_2s3() throws Exception {
|
||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -6393,6 +6393,24 @@ public class AST2CPPTests extends AST2BaseTest {
|
|||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(8).resolveBinding());
|
||||
}
|
||||
|
||||
// template <typename T> class A;
|
||||
// template <template<typename> class T> class A {};
|
||||
// template <template<typename> class T> class A;
|
||||
// template <template<typename> class T> class B {};
|
||||
// template <typename T> class B;
|
||||
// template <typename T> class B {};
|
||||
public void testInvalidClassRedeclaration_364226() throws Exception {
|
||||
final String code = getAboveComment();
|
||||
IASTTranslationUnit tu= parse(code, ParserLanguage.CPP, true, false);
|
||||
CPPNameCollector nc= new CPPNameCollector();
|
||||
tu.accept(nc);
|
||||
assertProblemBindings(nc, 4);
|
||||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(4).resolveBinding());
|
||||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(7).resolveBinding());
|
||||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(12).resolveBinding());
|
||||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(14).resolveBinding());
|
||||
}
|
||||
|
||||
// struct Foo {
|
||||
// void foo();
|
||||
// };
|
||||
|
|
|
@ -5583,4 +5583,59 @@ public class AST2TemplateTests extends AST2BaseTest {
|
|||
public void testDirectlyNestedAmbiguity_362976() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<typename T, T p1, T p2, T p3=T(), T p4=T(), T p5=T(),
|
||||
// T p6=T(), T p7=T(), T p8=T(), T p9=T(), T p10=T(),
|
||||
// T p11=T(), T p12=T(), T p13=T(), T p14=T(), T p15=T(),
|
||||
// T p16=T(), T p17=T(), T p18=T(), T p19=T(), T p20=T()
|
||||
// >
|
||||
// struct MaxOfN {
|
||||
// template<typename X, X x1, X x2> struct Max2 {
|
||||
// static const X result = (x1>x2)?x1:x2;
|
||||
// };
|
||||
// static const T result = Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,
|
||||
// (Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,p1,p2>::result),
|
||||
// p3>::result),p4>::result),p5>::result),p6>::result),p7>::result),p8>::result),
|
||||
// p9>::result),p10>::result),p11>::result),p12>::result),p13>::result),p14>::result),
|
||||
// p15>::result),p16>::result),p17>::result),p18>::result),p19>::result),p20>::result;
|
||||
// };
|
||||
// int main(){
|
||||
// return MaxOfN<int,1,2>::result;
|
||||
// }
|
||||
public void testNestedTemplateAmbiguity_363609() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// void m() {}
|
||||
// };
|
||||
// template <class T, void (T::*m)() = &T::m> struct B {};
|
||||
// void test() {
|
||||
// B<A> b1;
|
||||
// }
|
||||
public void testDefaultArgForNonTypeTemplateParameter_363743() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<class T> struct A {
|
||||
// bool b;
|
||||
// };
|
||||
// class B {
|
||||
// };
|
||||
// template<class T> T * func();
|
||||
// void test1() {
|
||||
// delete func<A<B>>(); // This line causes the NPE
|
||||
// }
|
||||
//
|
||||
// template<bool> struct C {
|
||||
// int* ptr;
|
||||
// };
|
||||
// void test2() {
|
||||
// int a = 0, b = 1;
|
||||
// delete C< a<b >::ptr;
|
||||
// delete C< A<B>::b >::ptr;
|
||||
// }
|
||||
public void testTemplateAmbiguityInDeleteExpression_364225() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ import java.io.IOException;
|
|||
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
import org.eclipse.cdt.core.parser.util.ASTPrinter;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
|
||||
import org.eclipse.cdt.internal.core.parser.ParserException;
|
||||
|
||||
|
@ -39,6 +41,13 @@ public class ClassTypeHelperTests extends AST2BaseTest {
|
|||
return new BindingAssertionHelper(code, true);
|
||||
}
|
||||
|
||||
// int a;
|
||||
// const int& b;
|
||||
public void testTemp() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
ASTPrinter.print(helper.getTranslationUnit());
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// A(const A& a);
|
||||
// };
|
||||
|
|
|
@ -278,4 +278,41 @@ public class FaultToleranceTests extends AST2BaseTest {
|
|||
p= getDeclaration(tu, 1);
|
||||
s= getDeclaration(tu, 2);
|
||||
}
|
||||
|
||||
// TINT* f(TINT* p) {
|
||||
// TINT* f1(TINT* p) {
|
||||
// TINT* f2(TINT* p) {
|
||||
// TINT* f3(TINT* p) {
|
||||
// TINT* f4(TINT* p) {
|
||||
// TINT* f5(TINT* p) {
|
||||
// TINT* f6(TINT* p) {
|
||||
// TINT* f7(TINT* p) {
|
||||
// TINT* f8(TINT* p) {
|
||||
// TINT* f9(TINT* p) {
|
||||
// TINT* f10(TINT* p) {
|
||||
// TINT* f11(TINT* p) {
|
||||
// TINT* f12(TINT* p) {
|
||||
// TINT* f13(TINT* p) {
|
||||
// TINT* f14(TINT* p) {
|
||||
// TINT* f15(TINT* p) {
|
||||
// TINT* f16(TINT* p) {
|
||||
// TINT* f17(TINT* p) {
|
||||
// TINT* f18(TINT* p) {
|
||||
// TINT* f19(TINT* p) {
|
||||
// TINT* f20(TINT* p) {
|
||||
// TINT* f21(TINT* p) {
|
||||
// TINT* f22(TINT* p) {
|
||||
// TINT* f23(TINT* p) {
|
||||
// TINT* f24(TINT* p) {
|
||||
// TINT* f25(TINT* p) {
|
||||
// TINT* f26(TINT* p) {
|
||||
// TINT* f27(TINT* p) {
|
||||
// TINT* f28(TINT* p) {
|
||||
// TINT* f29(TINT* p) {
|
||||
// }
|
||||
public void testPerformanceIssue_364108() throws Exception {
|
||||
final String comment= getAboveComment();
|
||||
parse(comment, ParserLanguage.CPP, false, false);
|
||||
parse(comment, ParserLanguage.C, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ public class GCCCompleteParseExtensionsTest extends AST2BaseTest {
|
|||
parseGPP( writer.toString() );
|
||||
|
||||
writer = new StringWriter();
|
||||
writer.write( "int x = ({ int foo() { return 1; } int y = foo (); int z;\n" ); //$NON-NLS-1$
|
||||
writer.write( "int x = ({ int foo(); int y = foo (); int z;\n" ); //$NON-NLS-1$
|
||||
writer.write( "if (y > 0) z = y;\n" ); //$NON-NLS-1$
|
||||
writer.write( "else z = - y;\n" );//$NON-NLS-1$
|
||||
writer.write( "z; });\n" );//$NON-NLS-1$
|
||||
|
|
|
@ -288,6 +288,42 @@ public class IndexNamesTests extends BaseTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
// class A {
|
||||
// virtual void foo(){}
|
||||
// template<typename C> void SetCallback(C callback){}
|
||||
// void InitCallback() {
|
||||
// SetCallback(&A::foo); // Can be A::foo or B::foo
|
||||
// }
|
||||
// };
|
||||
// class B: public A {
|
||||
// virtual void foo(){}
|
||||
// };
|
||||
public void testAddressOfPolymorphicMethod_Bug363731() throws Exception {
|
||||
waitForIndexer();
|
||||
String content= getComment();
|
||||
IFile file= createFile(getProject().getProject(), "test.cpp", content);
|
||||
waitUntilFileIsIndexed(file, 4000);
|
||||
|
||||
fIndex.acquireReadLock();
|
||||
try {
|
||||
IIndexFile ifile= getIndexFile(ILinkage.CPP_LINKAGE_ID, file);
|
||||
IIndexName[] names= ifile.findNames(0, content.length());
|
||||
int j= 0;
|
||||
for (IIndexName indexName : names) {
|
||||
if (indexName.isReference() && indexName.toString().equals("foo")) {
|
||||
assertEquals(true, indexName.couldBePolymorphicMethodCall());
|
||||
assertEquals("A", CPPVisitor.getQualifiedName(fIndex.findBinding(indexName))[0]);
|
||||
j++;
|
||||
} else {
|
||||
assertEquals(false, indexName.couldBePolymorphicMethodCall());
|
||||
}
|
||||
}
|
||||
assertEquals(1, j);
|
||||
} finally {
|
||||
fIndex.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
// int _i, ri, wi, rwi;
|
||||
// int* rp; int* wp; int* rwp;
|
||||
// const int* cip= &ri;
|
||||
|
|
|
@ -17,11 +17,10 @@ package org.eclipse.cdt.core.dom.ast;
|
|||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface IASTDeclarator extends IASTNode, IASTNameOwner {
|
||||
|
||||
/**
|
||||
* Constant - empty declarator array
|
||||
*/
|
||||
public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = new IASTDeclarator[0];
|
||||
public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = {};
|
||||
|
||||
/**
|
||||
* <code>POINTER_OPERATOR</code> represents the relationship between an
|
||||
|
@ -111,10 +110,12 @@ public interface IASTDeclarator extends IASTNode, IASTNameOwner {
|
|||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
@Override
|
||||
public IASTDeclarator copy();
|
||||
|
||||
/**
|
||||
* @since 5.3
|
||||
*/
|
||||
@Override
|
||||
public IASTDeclarator copy(CopyStyle style);
|
||||
}
|
||||
|
|
|
@ -15,19 +15,20 @@ package org.eclipse.cdt.core.dom.ast;
|
|||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface IASTPointerOperator extends IASTNode {
|
||||
|
||||
/**
|
||||
* Constant/sentinel.
|
||||
*/
|
||||
public static final IASTPointerOperator[] EMPTY_ARRAY = new IASTPointerOperator[0];
|
||||
public static final IASTPointerOperator[] EMPTY_ARRAY = {};
|
||||
|
||||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
@Override
|
||||
public IASTPointerOperator copy();
|
||||
|
||||
/**
|
||||
* @since 5.3
|
||||
*/
|
||||
@Override
|
||||
public IASTPointerOperator copy(CopyStyle style);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
|||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface ICPPASTReferenceOperator extends IASTPointerOperator {
|
||||
|
||||
/**
|
||||
* Returns whether the operator denotes a rvalue reference (e.g. <code>int &&</code>).
|
||||
* @since 5.2
|
||||
|
@ -30,10 +29,12 @@ public interface ICPPASTReferenceOperator extends IASTPointerOperator {
|
|||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
@Override
|
||||
public ICPPASTReferenceOperator copy();
|
||||
|
||||
/**
|
||||
* @since 5.3
|
||||
*/
|
||||
@Override
|
||||
public ICPPASTReferenceOperator copy(CopyStyle style);
|
||||
}
|
||||
|
|
|
@ -52,10 +52,9 @@ public class TypeHelper {
|
|||
}
|
||||
SizeofCalculator calc = ((ASTTranslationUnit) ast).getSizeofCalculator();
|
||||
SizeAndAlignment sizeofPointer = calc.sizeAndAlignmentOfPointer();
|
||||
if (sizeofPointer == null)
|
||||
return true;
|
||||
long maxSize = sizeofPointer != null ? sizeofPointer.size : 4;
|
||||
SizeAndAlignment sizeofType = calc.sizeAndAlignment(type);
|
||||
if (sizeofType == null || sizeofType.size > sizeofPointer.size)
|
||||
if (sizeofType == null || sizeofType.size > maxSize)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -90,6 +90,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
|
|||
*/
|
||||
public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||
public interface ITemplateIdStrategy {
|
||||
boolean shallParseAsTemplateID(IASTName name);
|
||||
}
|
||||
|
||||
protected static class FoundAggregateInitializer extends Exception {
|
||||
|
@ -243,6 +244,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
throw backtrack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTCompletionNode getCompletionNode() {
|
||||
return completionNode;
|
||||
}
|
||||
|
@ -555,6 +557,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
parsePassed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cancel() {
|
||||
isCancelled = true;
|
||||
}
|
||||
|
@ -642,6 +645,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
throwBacktrack(n.getOffset(), n.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTTranslationUnit parse() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
translationUnit();
|
||||
|
@ -1173,22 +1177,27 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
return fUnaryOperatorOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression copy() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression copy(CopyStyle style) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getExpressionType() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueCategory getValueCategory() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -1198,12 +1207,15 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
if (LT(1) == IToken.tLPAREN) {
|
||||
final IToken mark= mark();
|
||||
final int startingOffset= mark.getOffset();
|
||||
final boolean canBeCast= canBeCastExpression();
|
||||
consume();
|
||||
IASTTypeId typeId= null;
|
||||
if (canBeCast) {
|
||||
try {
|
||||
typeId= typeId(DeclarationOptions.TYPEID);
|
||||
} catch (BacktrackException e) {
|
||||
}
|
||||
}
|
||||
if (typeId != null && LT(1) == IToken.tRPAREN) {
|
||||
consume();
|
||||
boolean unaryFailed= false;
|
||||
|
@ -1562,6 +1574,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
return skipProblemConditionInParenthesis(mark.getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encounteredError() {
|
||||
return !parsePassed;
|
||||
}
|
||||
|
@ -1862,9 +1875,11 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
ds = nodeFactory.newDeclarationStatement(d);
|
||||
setRange(ds, d);
|
||||
} catch (BacktrackException b) {
|
||||
if (expressionStatement == null) {
|
||||
IASTNode node = b.getNodeBeforeProblem();
|
||||
if (node instanceof IASTDeclaration) {
|
||||
final boolean isProblemDecl = node instanceof IASTDeclaration;
|
||||
if (expressionStatement == null
|
||||
|| (!foundSemicolon && isProblemDecl && node.contains(expressionStatement))) {
|
||||
if (isProblemDecl) {
|
||||
ds= nodeFactory.newDeclarationStatement((IASTDeclaration) node);
|
||||
b.initialize(b.getProblem(), setRange(ds, node));
|
||||
}
|
||||
|
@ -2399,7 +2414,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
if (token.getType() == IGCCToken.t__declspec) {
|
||||
consume();
|
||||
if (LT(1) == IToken.tLPAREN) {
|
||||
skipBrackets(IToken.tLPAREN, IToken.tRPAREN);
|
||||
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2433,24 +2448,68 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In case a cast expression is followed by +/- or & we should avoid it:
|
||||
* (a)+1 vs. (int)+1;
|
||||
* @since 4.0
|
||||
*/
|
||||
protected boolean avoidCastExpressionByHeuristics() throws EndOfFileException {
|
||||
if (LT(1) == IToken.tIDENTIFIER) {
|
||||
if (LT(2) == IToken.tRPAREN) {
|
||||
switch (LT(3)) {
|
||||
case IToken.tPLUS:
|
||||
case IToken.tMINUS:
|
||||
case IToken.tAMPER:
|
||||
case IToken.tSTAR:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected boolean canBeCompoundLiteral() throws EndOfFileException {
|
||||
IToken m= mark();
|
||||
try {
|
||||
// The parenthesis cannot be followed by a binary operator
|
||||
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
|
||||
return LTcatchEOF(1) == IToken.tLBRACE;
|
||||
} catch (BacktrackException bt) {
|
||||
return false;
|
||||
} finally {
|
||||
backup(m);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canBeCastExpression() throws EndOfFileException {
|
||||
IToken m= mark();
|
||||
try {
|
||||
// The parenthesis cannot be followed by a binary operator
|
||||
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
|
||||
switch (LTcatchEOF(1)) {
|
||||
case IToken.tAMPERASSIGN:
|
||||
case IToken.tAND:
|
||||
case IToken.tARROW:
|
||||
case IToken.tARROWSTAR:
|
||||
case IToken.tASSIGN:
|
||||
case IToken.tBITOR:
|
||||
case IToken.tBITORASSIGN:
|
||||
case IToken.tCOLON:
|
||||
case IToken.tCOMMA:
|
||||
case IToken.tDIV:
|
||||
case IToken.tDIVASSIGN:
|
||||
case IToken.tDOT:
|
||||
case IToken.tDOTSTAR:
|
||||
case IToken.tEQUAL:
|
||||
case IToken.tGT:
|
||||
case IToken.tGT_in_SHIFTR:
|
||||
case IToken.tGTEQUAL:
|
||||
case IToken.tLBRACKET:
|
||||
case IToken.tLTEQUAL:
|
||||
case IToken.tMINUSASSIGN:
|
||||
case IToken.tMOD:
|
||||
case IToken.tMODASSIGN:
|
||||
case IToken.tNOTEQUAL:
|
||||
case IToken.tOR:
|
||||
case IToken.tPLUSASSIGN:
|
||||
case IToken.tQUESTION:
|
||||
case IToken.tRBRACE:
|
||||
case IToken.tRBRACKET:
|
||||
case IToken.tRPAREN:
|
||||
case IToken.tSEMI:
|
||||
case IToken.tSHIFTL:
|
||||
case IToken.tSHIFTLASSIGN:
|
||||
case IToken.tSHIFTR:
|
||||
case IToken.tSHIFTRASSIGN:
|
||||
case IToken.tSTARASSIGN:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (BacktrackException bt) {
|
||||
return false;
|
||||
} finally {
|
||||
backup(m);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canBeTypeSpecifier() throws EndOfFileException {
|
||||
|
@ -2511,12 +2570,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
}
|
||||
}
|
||||
|
||||
protected void skipBrackets(int left, int right) throws EndOfFileException, BacktrackException {
|
||||
protected void skipBrackets(int left, int right, int terminator) throws EndOfFileException, BacktrackException {
|
||||
consume(left);
|
||||
int nesting= 0;
|
||||
while(true) {
|
||||
final int lt1= LT(1);
|
||||
if (lt1 == IToken.tEOC)
|
||||
if (lt1 == IToken.tEOC || lt1 == terminator)
|
||||
throwBacktrack(LA(1));
|
||||
|
||||
consume();
|
||||
|
|
|
@ -29,16 +29,17 @@ public class DeclarationOptions {
|
|||
final public static int ALLOW_FOLLOWED_BY_BRACE= 0x1000;
|
||||
final public static int ALLOW_OPAQUE_ENUM= 0x2000;
|
||||
final public static int SINGLE_DTOR= 0x4000;
|
||||
final public static int ALLOW_FUNCTION_DEFINITION= 0x8000;
|
||||
|
||||
public static final DeclarationOptions
|
||||
GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM),
|
||||
FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT),
|
||||
GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM | ALLOW_FUNCTION_DEFINITION),
|
||||
FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT | ALLOW_FUNCTION_DEFINITION),
|
||||
C_MEMBER= new DeclarationOptions(ALLOW_BITFIELD | ALLOW_ABSTRACT),
|
||||
CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER),
|
||||
CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER | ALLOW_FUNCTION_DEFINITION),
|
||||
LOCAL= new DeclarationOptions(ALLOW_OPAQUE_ENUM),
|
||||
PARAMETER= new DeclarationOptions(ALLOW_ABSTRACT | ALLOW_PARAMETER_PACKS | REQUIRE_SIMPLE_NAME | NO_BRACED_INITIALIZER | NO_CTOR_STYLE_INITIALIZER),
|
||||
TYPEID= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER),
|
||||
TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE),
|
||||
TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE | ALLOW_FUNCTION_DEFINITION),
|
||||
TYPEID_NEW= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED | ALLOW_FOLLOWED_BY_BRACE),
|
||||
TYPEID_CONVERSION= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED),
|
||||
EXCEPTION= new DeclarationOptions(ALLOW_ABSTRACT | NO_INITIALIZER),
|
||||
|
@ -60,6 +61,7 @@ public class DeclarationOptions {
|
|||
final public boolean fRequireSimpleName;
|
||||
final public boolean fAllowOpaqueEnum;
|
||||
final public boolean fSingleDtor;
|
||||
final public boolean fAllowFunctionDefinition;
|
||||
|
||||
public DeclarationOptions(int options) {
|
||||
fAllowEmptySpecifier= (options & ALLOW_EMPTY_SPECIFIER) != 0;
|
||||
|
@ -76,5 +78,6 @@ public class DeclarationOptions {
|
|||
fCanBeFollowedByBrace= fAllowBracedInitializer || (options & ALLOW_FOLLOWED_BY_BRACE) != 0;
|
||||
fAllowOpaqueEnum= (options & ALLOW_OPAQUE_ENUM) != 0;
|
||||
fSingleDtor= (options & SINGLE_DTOR) != 0;
|
||||
fAllowFunctionDefinition= (options & ALLOW_FUNCTION_DEFINITION) != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1754,7 +1754,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
|||
final IToken current = LA(1);
|
||||
int startingOffset = current.getOffset();
|
||||
if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) {
|
||||
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET);
|
||||
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
|
||||
}
|
||||
|
||||
IASTDeclSpecifier declSpec = null;
|
||||
|
|
|
@ -19,21 +19,23 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
|||
* Reference operator for declarators.
|
||||
*/
|
||||
public class CPPASTReferenceOperator extends ASTNode implements ICPPASTReferenceOperator {
|
||||
|
||||
private final boolean fIsRValue;
|
||||
|
||||
public CPPASTReferenceOperator(boolean isRValueReference) {
|
||||
fIsRValue= isRValueReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRValueReference() {
|
||||
return fIsRValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPPASTReferenceOperator copy() {
|
||||
return copy(CopyStyle.withoutLocations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPPASTReferenceOperator copy(CopyStyle style) {
|
||||
CPPASTReferenceOperator copy = new CPPASTReferenceOperator(fIsRValue);
|
||||
copy.setOffsetAndLength(this);
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.Value;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
|
||||
|
@ -40,6 +41,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
|
|||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTExpression getDefault() {
|
||||
IASTInitializerClause def= getDefaultClause();
|
||||
if (def instanceof IASTExpression) {
|
||||
|
@ -59,7 +61,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
|
|||
IASTNode parent = name.getParent();
|
||||
assert parent instanceof IASTDeclarator;
|
||||
if (parent instanceof IASTDeclarator) {
|
||||
IASTDeclarator dtor = (IASTDeclarator) parent;
|
||||
IASTDeclarator dtor = ASTQueries.findOutermostDeclarator((IASTDeclarator) parent);
|
||||
IASTInitializer initializer = dtor.getInitializer();
|
||||
if (initializer instanceof IASTEqualsInitializer) {
|
||||
return ((IASTEqualsInitializer) initializer).getInitializerClause();
|
||||
|
@ -70,6 +72,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPTemplateArgument getDefaultValue() {
|
||||
IASTInitializerClause dc= getDefault();
|
||||
IASTExpression d= null;
|
||||
|
@ -96,6 +99,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
|
|||
return new CPPTemplateArgument(val, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IType getType() {
|
||||
if (type == null) {
|
||||
IASTNode parent= getPrimaryDeclaration().getParent();
|
||||
|
@ -110,28 +114,36 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
|
|||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParameterPack() {
|
||||
return getType() instanceof ICPPParameterPackType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isExtern() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isAuto() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isRegister() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public IValue getInitialValue() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean isExternC() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -209,11 +209,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
|
||||
private IASTName qualifiedName() throws BacktrackException, EndOfFileException {
|
||||
return ambiguousQualifiedName(CastExprCtx.eNotInBExpr);
|
||||
}
|
||||
|
||||
private IASTName ambiguousQualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||
IToken m= mark();
|
||||
for(;;) {
|
||||
try {
|
||||
return qualifiedName(strat, CastExprCtx.eNotInBExpr);
|
||||
return qualifiedName(ctx, strat);
|
||||
} catch (BacktrackException e) {
|
||||
if (strat.setNextAlternative()) {
|
||||
backup(m);
|
||||
|
@ -227,8 +231,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
/**
|
||||
* Parses a qualified name.
|
||||
*/
|
||||
private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
||||
final TemplateIdStrategy strat= (TemplateIdStrategy) s;
|
||||
private IASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
|
||||
if (strat == null)
|
||||
return ambiguousQualifiedName(ctx);
|
||||
|
||||
ICPPASTQualifiedName qname= null;
|
||||
IASTName name= null;
|
||||
final int offset= LA(1).getOffset();
|
||||
|
@ -288,11 +294,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
if (haveArgs == -1) {
|
||||
templateID= false;
|
||||
} else if (haveArgs == 0) {
|
||||
if (strat.ignoreTemplateID()) {
|
||||
templateID= false;
|
||||
} else {
|
||||
strat.addTemplateName(name);
|
||||
}
|
||||
templateID= strat.shallParseAsTemplateID(name);
|
||||
}
|
||||
}
|
||||
if (templateID) {
|
||||
|
@ -350,7 +352,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return name;
|
||||
}
|
||||
|
||||
private IASTName addTemplateArguments(IASTName templateName, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTName addTemplateArguments(IASTName templateName, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
// Parse for template arguments
|
||||
consume(IToken.tLT);
|
||||
List<IASTNode> list = templateArgumentList(strat);
|
||||
|
@ -566,7 +568,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
}
|
||||
|
||||
private List<IASTNode> templateArgumentList(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private List<IASTNode> templateArgumentList(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
int startingOffset = LA(1).getOffset();
|
||||
int endOffset = 0;
|
||||
List<IASTNode> list= null;
|
||||
|
@ -596,7 +598,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return list;
|
||||
}
|
||||
|
||||
private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
IToken argStart = mark();
|
||||
ICPPASTTypeId typeId= null;
|
||||
int lt1= 0;
|
||||
|
@ -742,7 +744,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null);
|
||||
}
|
||||
|
||||
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
final boolean allowComma= kind==ExprKind.eExpression;
|
||||
boolean allowAssignment= kind !=ExprKind.eConstant;
|
||||
|
||||
|
@ -750,12 +752,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return throwExpression();
|
||||
}
|
||||
|
||||
final boolean handleVariants= strat == null;
|
||||
if (handleVariants) {
|
||||
strat= new TemplateIdStrategy();
|
||||
}
|
||||
|
||||
|
||||
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
|
||||
int lt1;
|
||||
int conditionCount= 0;
|
||||
|
@ -763,7 +759,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
NameOrTemplateIDVariants variants= null;
|
||||
|
||||
if (expr == null) {
|
||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
||||
Object e = castExpressionForBinaryExpression(strat);
|
||||
if (e instanceof IASTExpression) {
|
||||
expr= (IASTExpression) e;
|
||||
} else {
|
||||
|
@ -934,7 +930,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
// Cast expression
|
||||
IToken m= mark();
|
||||
try {
|
||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
||||
Object e = castExpressionForBinaryExpression(strat);
|
||||
if (e instanceof IASTExpression) {
|
||||
expr= (IASTExpression) e;
|
||||
} else {
|
||||
|
@ -999,18 +995,19 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return buildExpression(lastOperator, expr);
|
||||
}
|
||||
|
||||
public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat)
|
||||
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
|
||||
throws EndOfFileException, BacktrackException {
|
||||
if (!handleVariants)
|
||||
return castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||
if (s != null) {
|
||||
return castExpression(CastExprCtx.eDirectlyInBExpr, s);
|
||||
}
|
||||
|
||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||
Variant variants= null;
|
||||
IASTExpression singleExpression= null;
|
||||
IASTName[] firstNames= null;
|
||||
|
||||
final IToken mark= mark();
|
||||
IToken lastToken= null;
|
||||
strat.reset();
|
||||
for(;;) {
|
||||
try {
|
||||
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||
|
@ -1454,6 +1451,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
// ( type-name ) { initializer-list , }
|
||||
IToken m = mark();
|
||||
try {
|
||||
if (canBeCompoundLiteral()) {
|
||||
int offset = consume().getOffset();
|
||||
IASTTypeId t= typeId(DeclarationOptions.TYPEID);
|
||||
consume(IToken.tRPAREN);
|
||||
|
@ -1463,6 +1461,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
setRange(firstExpression, offset, calculateEndOffset(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (BacktrackException bt) {
|
||||
}
|
||||
backup(m);
|
||||
|
@ -1554,7 +1553,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
isTemplate = true;
|
||||
}
|
||||
|
||||
IASTName name = qualifiedName(strat, ctx);
|
||||
IASTName name = qualifiedName(ctx, strat);
|
||||
|
||||
if (name == null)
|
||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||
|
@ -1577,7 +1576,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
isTemplate = true;
|
||||
}
|
||||
|
||||
name = qualifiedName(strat, ctx);
|
||||
name = qualifiedName(ctx, strat);
|
||||
|
||||
if (name == null)
|
||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||
|
@ -1690,7 +1689,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
case IToken.t_operator:
|
||||
case IToken.tCOMPLETION:
|
||||
case IToken.tBITCOMPLEMENT: {
|
||||
IASTName name = qualifiedName(strat, ctx);
|
||||
IASTName name = qualifiedName(ctx, strat);
|
||||
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
|
||||
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
|
||||
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
|
||||
|
@ -2388,7 +2387,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
case IToken.t_try:
|
||||
case IToken.tLBRACE:
|
||||
case IToken.tASSIGN: // defaulted or deleted function definition
|
||||
if (declarators.length != 1)
|
||||
if (declarators.length != 1 || !declOption.fAllowFunctionDefinition)
|
||||
throwBacktrack(LA(1));
|
||||
|
||||
dtor= declarators[0];
|
||||
|
@ -2568,7 +2567,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
final int startOffset= LA(1).getOffset();
|
||||
|
||||
if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) {
|
||||
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET);
|
||||
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
|
||||
}
|
||||
|
||||
IASTDeclSpecifier declSpec= null;
|
||||
|
|
|
@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
|||
import java.util.BitSet;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy;
|
||||
|
||||
|
@ -27,50 +29,52 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
|
|||
private IASTName[] fTemplateNames;
|
||||
|
||||
public TemplateIdStrategy() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
fCurrentBranchPoint= -1;
|
||||
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
|
||||
if (fSimpleIDs != null) {
|
||||
fSimpleIDs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ignoreTemplateID() {
|
||||
@Override
|
||||
public boolean shallParseAsTemplateID(IASTName name) {
|
||||
fCurrentBranchPoint++;
|
||||
return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint);
|
||||
}
|
||||
|
||||
public void addTemplateName(IASTName name) {
|
||||
boolean templateID= fSimpleIDs == null || !fSimpleIDs.get(fCurrentBranchPoint);
|
||||
if (templateID) {
|
||||
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
|
||||
}
|
||||
return templateID;
|
||||
}
|
||||
|
||||
public boolean setNextAlternative() {
|
||||
final int bp = fCurrentBranchPoint;
|
||||
int bp = fCurrentBranchPoint;
|
||||
if (bp < 0)
|
||||
return false;
|
||||
|
||||
fCurrentBranchPoint= -1;
|
||||
IASTName[] names = getTemplateNames();
|
||||
int nameLen= names.length;
|
||||
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
|
||||
if (fSimpleIDs == null) {
|
||||
fSimpleIDs= new BitSet();
|
||||
}
|
||||
|
||||
// Set a new branch as far right as possible.
|
||||
final int len = fSimpleIDs.length();
|
||||
if (len <= bp) {
|
||||
while (bp >= 0) {
|
||||
if (!fSimpleIDs.get(bp)) {
|
||||
if (nameLen == 0 || !hasMultipleArgs(names[--nameLen])) {
|
||||
fSimpleIDs.clear(bp+1, Integer.MAX_VALUE);
|
||||
fSimpleIDs.set(bp);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int branch= Math.min(bp, len-2); branch>=0; branch--) {
|
||||
if (!fSimpleIDs.get(branch)) {
|
||||
fSimpleIDs.clear(branch+1, len);
|
||||
fSimpleIDs.set(branch);
|
||||
return true;
|
||||
}
|
||||
bp--;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasMultipleArgs(IASTName templateName) {
|
||||
IASTNode parent= templateName.getParent();
|
||||
if (parent instanceof ICPPASTTemplateId) {
|
||||
return ((ICPPASTTemplateId) parent).getTemplateArguments().length > 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -781,7 +781,9 @@ public class CPPSemantics {
|
|||
data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results);
|
||||
}
|
||||
} else {
|
||||
data.foundItems = mergePrefixResults((CharArrayObjectMap) data.foundItems, results, scoped);
|
||||
@SuppressWarnings("unchecked")
|
||||
final CharArrayObjectMap<Object> oldItems = (CharArrayObjectMap<Object>) data.foundItems;
|
||||
data.foundItems = mergePrefixResults(oldItems, results, scoped);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,15 +793,17 @@ public class CPPSemantics {
|
|||
* @param scoped
|
||||
* @return
|
||||
*/
|
||||
static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) {
|
||||
static CharArrayObjectMap<Object> mergePrefixResults(CharArrayObjectMap<Object> dest, Object source, boolean scoped) {
|
||||
if (source == null) return dest;
|
||||
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
|
||||
CharArrayObjectMap<Object> resultMap = (dest != null) ? dest : new CharArrayObjectMap<Object>(2);
|
||||
|
||||
CharArrayObjectMap map = null;
|
||||
CharArrayObjectMap<Object> map = null;
|
||||
Object[] objs = null;
|
||||
int size;
|
||||
if (source instanceof CharArrayObjectMap) {
|
||||
map = (CharArrayObjectMap) source;
|
||||
@SuppressWarnings("unchecked")
|
||||
final CharArrayObjectMap<Object> sourceMap = (CharArrayObjectMap<Object>) source;
|
||||
map = sourceMap;
|
||||
size= map.size();
|
||||
} else {
|
||||
if (source instanceof Object[])
|
||||
|
@ -3499,7 +3503,7 @@ public class CPPSemantics {
|
|||
LookupData data = createLookupData(name);
|
||||
data.contentAssist = true;
|
||||
data.prefixLookup = prefixLookup;
|
||||
data.foundItems = new CharArrayObjectMap(2);
|
||||
data.foundItems = new CharArrayObjectMap<Object>(2);
|
||||
|
||||
// Convert namespaces to scopes.
|
||||
List<ICPPScope> nsScopes= new ArrayList<ICPPScope>();
|
||||
|
@ -3567,7 +3571,8 @@ public class CPPSemantics {
|
|||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems;
|
||||
@SuppressWarnings("unchecked")
|
||||
CharArrayObjectMap<Object> map = (CharArrayObjectMap<Object>) data.foundItems;
|
||||
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
|
||||
if (!map.isEmpty()) {
|
||||
char[] key = null;
|
||||
|
@ -3686,7 +3691,7 @@ public class CPPSemantics {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
|
||||
static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
|
||||
if (tp1.isParameterPack() != tp2.isParameterPack())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -460,10 +460,9 @@ public class CPPVisitor extends ASTQueries {
|
|||
}
|
||||
|
||||
try {
|
||||
boolean template = false;
|
||||
ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name);
|
||||
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
||||
while (scope instanceof ICPPTemplateScope) {
|
||||
template = true;
|
||||
scope= (ICPPScope) scope.getParent();
|
||||
}
|
||||
|
||||
|
@ -493,14 +492,35 @@ public class CPPVisitor extends ASTQueries {
|
|||
|
||||
if (binding instanceof ICPPClassType) {
|
||||
final ICPPInternalBinding ib = (ICPPInternalBinding) binding;
|
||||
if ((binding instanceof ICPPClassTemplate) == template) {
|
||||
if (templateParametersMatch((ICPPClassType) binding, templateDecl)) {
|
||||
ib.addDeclaration(elabType);
|
||||
return binding;
|
||||
}
|
||||
if (CPPSemantics.declaredBefore(binding, name, false)) {
|
||||
|
||||
if (CPPSemantics.declaredBefore(ib, name, false)) {
|
||||
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION);
|
||||
}
|
||||
markRedeclaration(ib);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a binding
|
||||
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
|
||||
if (templateDecl != null)
|
||||
binding = new CPPClassTemplate(name);
|
||||
else
|
||||
binding = new CPPClassType(name, binding);
|
||||
// name may live in a different scope, so make sure to add it to the owner scope, as well.
|
||||
ASTInternal.addName(scope, elabType.getName());
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
binding = e.getProblem();
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
public static void markRedeclaration(final ICPPInternalBinding ib) {
|
||||
// Mark the other declarations as problem and create the binding
|
||||
final IASTNode[] decls = ib.getDeclarations();
|
||||
if (decls != null) {
|
||||
|
@ -517,22 +537,30 @@ public class CPPVisitor extends ASTQueries {
|
|||
n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a binding
|
||||
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
|
||||
if (template)
|
||||
binding = new CPPClassTemplate(name);
|
||||
else
|
||||
binding = new CPPClassType(name, binding);
|
||||
// name may live in a different scope, so make sure to add it to the owner scope, as well.
|
||||
ASTInternal.addName(scope, elabType.getName());
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
binding = e.getProblem();
|
||||
}
|
||||
/**
|
||||
* Tests whether a class binding matches the template parameters of another declaration
|
||||
*/
|
||||
private static boolean templateParametersMatch(ICPPClassType binding,
|
||||
ICPPASTTemplateDeclaration templateDecl) {
|
||||
final boolean isTemplate= binding instanceof ICPPClassTemplate;
|
||||
if (templateDecl == null)
|
||||
return !isTemplate;
|
||||
if (!isTemplate)
|
||||
return false;
|
||||
|
||||
return binding;
|
||||
ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters();
|
||||
ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters();
|
||||
|
||||
int i=0;
|
||||
for (ICPPASTTemplateParameter p2 : pars2) {
|
||||
if (i >= pars1.length)
|
||||
return true;
|
||||
|
||||
if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) {
|
||||
|
@ -541,39 +569,43 @@ public class CPPVisitor extends ASTQueries {
|
|||
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
|
||||
name = ns[ns.length - 1];
|
||||
}
|
||||
if (name instanceof ICPPASTTemplateId)
|
||||
return CPPTemplates.createBinding((ICPPASTTemplateId) name);
|
||||
|
||||
IBinding binding = null;
|
||||
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
||||
try {
|
||||
boolean template = false;
|
||||
while (scope instanceof ICPPTemplateScope) {
|
||||
template = true;
|
||||
scope= (ICPPScope) scope.getParent();
|
||||
}
|
||||
if (name instanceof ICPPASTTemplateId) {
|
||||
return CPPTemplates.createBinding((ICPPASTTemplateId) name);
|
||||
}
|
||||
if (name.getLookupKey().length > 0 && scope != null) // can't lookup anonymous things
|
||||
binding = scope.getBinding(name, false);
|
||||
if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) {
|
||||
ICPPInternalBinding internal = (ICPPInternalBinding) binding;
|
||||
if (internal.getDefinition() == null && (binding instanceof ICPPClassTemplate) == template) {
|
||||
ASTInternal.addDefinition(internal, compType);
|
||||
} else {
|
||||
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION);
|
||||
}
|
||||
} else {
|
||||
if (template) {
|
||||
binding = new CPPClassTemplate(name);
|
||||
} else {
|
||||
binding = new CPPClassType(name, binding);
|
||||
}
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
binding = e.getProblem();
|
||||
return e.getProblem();
|
||||
}
|
||||
|
||||
// Can't lookup anonymous names
|
||||
IBinding binding= null;
|
||||
ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name);
|
||||
if (name.getLookupKey().length > 0 && scope != null) {
|
||||
binding = scope.getBinding(name, false);
|
||||
|
||||
if (binding instanceof ICPPInternalBinding
|
||||
&& binding instanceof ICPPClassType && name.isActive()) {
|
||||
ICPPInternalBinding ib = (ICPPInternalBinding) binding;
|
||||
if (ib.getDefinition() == null
|
||||
&& templateParametersMatch((ICPPClassType) binding, templateDecl)) {
|
||||
ASTInternal.addDefinition(ib, compType);
|
||||
return binding;
|
||||
}
|
||||
if (CPPSemantics.declaredBefore(ib, name, false)) {
|
||||
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION);
|
||||
}
|
||||
markRedeclaration(ib);
|
||||
}
|
||||
}
|
||||
if (templateDecl != null)
|
||||
return new CPPClassTemplate(name);
|
||||
|
||||
return new CPPClassType(name, binding);
|
||||
}
|
||||
|
||||
private static IBinding createBinding(IASTDeclaration declaration) {
|
||||
if (declaration instanceof ICPPASTNamespaceDefinition) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IScope;
|
|||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||
|
@ -110,6 +111,7 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
return IIndexCPPBindingConstants.CPPMETHOD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVirtual() {
|
||||
return getBit(getAnnotation1(), PDOMCPPAnnotation.VIRTUAL_OFFSET);
|
||||
}
|
||||
|
@ -120,10 +122,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
return annotation1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPureVirtual() {
|
||||
return getBit(getAnnotation1(), PDOMCPPAnnotation.PURE_VIRTUAL_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDestructor() {
|
||||
return getBit(getAnnotation1(), PDOMCPPAnnotation.DESTRUCTOR_OFFSET);
|
||||
}
|
||||
|
@ -133,10 +137,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImplicit() {
|
||||
return getBit(getAnnotation1(), PDOMCPPAnnotation.IMPLICIT_METHOD_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicit() {
|
||||
return getBit(getAnnotation1(), PDOMCPPAnnotation.EXPLICIT_METHOD_OFFSET);
|
||||
}
|
||||
|
@ -169,10 +175,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVisibility() {
|
||||
return PDOMCPPAnnotation.getVisibility(getAnnotation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPClassType getClassOwner() {
|
||||
return (ICPPClassType) getOwner();
|
||||
}
|
||||
|
@ -194,8 +202,19 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
public int getAdditionalNameFlags(int standardFlags, IASTName name) {
|
||||
if ((standardFlags & PDOMName.IS_REFERENCE) == PDOMName.IS_REFERENCE) {
|
||||
IASTNode parent= name.getParent();
|
||||
if (parent instanceof ICPPASTFieldReference) {
|
||||
// the name is not qualified
|
||||
if (parent instanceof ICPPASTQualifiedName) {
|
||||
// When taking the address of a method it will be called without suppressing
|
||||
// the virtual mechanism
|
||||
parent= parent.getParent();
|
||||
if (parent instanceof IASTIdExpression) {
|
||||
parent= parent.getParent();
|
||||
if (parent instanceof IASTUnaryExpression) {
|
||||
if (((IASTUnaryExpression) parent).getOperator() == IASTUnaryExpression.op_amper)
|
||||
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof ICPPASTFieldReference) {
|
||||
// The name is not qualified
|
||||
ICPPASTFieldReference fr= (ICPPASTFieldReference) parent;
|
||||
parent= parent.getParent();
|
||||
if (parent instanceof IASTFunctionCallExpression) {
|
||||
|
@ -221,9 +240,8 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
|
|||
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// calling a member from within a member
|
||||
else if (parent instanceof IASTIdExpression) {
|
||||
} else if (parent instanceof IASTIdExpression) {
|
||||
// Calling a member from within a member
|
||||
if (parent.getParent() instanceof IASTFunctionCallExpression) {
|
||||
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -132,7 +132,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -177,7 +177,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -240,7 +240,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -281,7 +281,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -343,7 +343,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -384,7 +384,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -450,7 +450,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -499,7 +499,7 @@ public:
|
|||
this->systemId = systemId;
|
||||
}
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -704,53 +704,37 @@ class test {
|
|||
|
||||
#endif /* TEST_H_ */
|
||||
|
||||
//!Generate Getters and Setters One Getter Selection Separate Definition
|
||||
//!Generate Getters and Setters, Pass by Reference, Separate Definition
|
||||
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
|
||||
//@.config
|
||||
filename=C.h
|
||||
getters=name
|
||||
setters=name
|
||||
definitionSeparate=true
|
||||
//@C.cpp
|
||||
#include "C.h"
|
||||
|
||||
int Person::SocSecNo() {
|
||||
return socSecNo;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//=
|
||||
#include "C.h"
|
||||
|
||||
char* Person::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
int Person::SocSecNo() {
|
||||
return socSecNo;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//@C.h
|
||||
#ifndef C_H_
|
||||
#define C_H_
|
||||
|
||||
struct FullName {
|
||||
const char* first;
|
||||
const char* last;
|
||||
FullName(const FullName& other);
|
||||
~FullName();
|
||||
};
|
||||
|
||||
class Person {
|
||||
private:
|
||||
int systemId;
|
||||
|
||||
protected:
|
||||
char* name;
|
||||
FullName name;
|
||||
|
||||
public:
|
||||
const int socSecNo;
|
||||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -774,20 +758,28 @@ int gooo = 1;
|
|||
#ifndef C_H_
|
||||
#define C_H_
|
||||
|
||||
struct FullName {
|
||||
const char* first;
|
||||
const char* last;
|
||||
FullName(const FullName& other);
|
||||
~FullName();
|
||||
};
|
||||
|
||||
class Person {
|
||||
private:
|
||||
int systemId;
|
||||
|
||||
protected:
|
||||
char* name;
|
||||
FullName name;
|
||||
|
||||
public:
|
||||
const int socSecNo;
|
||||
|
||||
Person myFriend;
|
||||
char* getName() const;
|
||||
const FullName& getName() const;
|
||||
void setName(const FullName& name);
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -807,6 +799,34 @@ public:
|
|||
int gooo = 1;
|
||||
|
||||
#endif /* C_H_ */
|
||||
//@C.cpp
|
||||
#include "C.h"
|
||||
|
||||
int Person::SocSecNo() {
|
||||
return socSecNo;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//=
|
||||
#include "C.h"
|
||||
|
||||
const FullName& Person::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
void Person::setName(const FullName& name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
int Person::SocSecNo() {
|
||||
return socSecNo;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//!Generate Getters and Setters One Getter Selection with Namespace Separate Definition
|
||||
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
|
||||
//@.config
|
||||
|
@ -863,7 +883,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -908,7 +928,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -984,7 +1004,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -1025,7 +1045,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -1102,7 +1122,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
@ -1144,7 +1164,7 @@ public:
|
|||
|
||||
Person myFriend;
|
||||
|
||||
Person(int socSecNo); // contructor
|
||||
Person(int socSecNo); // constructor
|
||||
|
||||
~Person(); // destructor
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ public class CHQueries {
|
|||
if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) {
|
||||
while (true) {
|
||||
ICElement[] defs= null;
|
||||
if (binding instanceof ICPPMethod) {
|
||||
if (binding instanceof ICPPMethod && name.couldBePolymorphicMethodCall()) {
|
||||
defs = findOverriders(index, (ICPPMethod) binding);
|
||||
}
|
||||
if (defs == null) {
|
||||
|
|
|
@ -24,7 +24,9 @@ import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
||||
import org.eclipse.cdt.core.dom.rewrite.TypeHelper;
|
||||
import org.eclipse.cdt.core.parser.Keywords;
|
||||
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression;
|
||||
|
@ -37,28 +39,39 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReferenceOperator;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
|
||||
public class FunctionFactory {
|
||||
public class GetterSetterFactory {
|
||||
private final IASTName fieldName;
|
||||
private final IASTSimpleDeclaration fieldDeclaration;
|
||||
private boolean passByReference;
|
||||
|
||||
public static IASTFunctionDefinition createGetterDefinition(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
|
||||
public GetterSetterFactory(IASTName fieldName, IASTSimpleDeclaration fieldDeclaration) {
|
||||
this.fieldName = fieldName;
|
||||
this.fieldDeclaration = fieldDeclaration;
|
||||
IType type = CPPVisitor.createType(fieldDeclaration.getDeclSpecifier());
|
||||
passByReference = TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit());
|
||||
}
|
||||
|
||||
public IASTFunctionDefinition createGetterDefinition(ICPPASTQualifiedName qualifiedName) {
|
||||
IASTFunctionDefinition getter = new CPPASTFunctionDefinition();
|
||||
|
||||
getter.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations));
|
||||
IASTDeclarator getterDeclarator = getGetterDeclarator(fieldName, fieldDeclaration, name);
|
||||
// IASTFunctionDefinition. expects the outermost IASTFunctionDeclarator in declarator hierarchy
|
||||
getter.setDeclSpecifier(getParamOrReturnDeclSpecifier());
|
||||
IASTDeclarator getterDeclarator = getGetterDeclarator(qualifiedName);
|
||||
// IASTFunctionDefinition expects the outermost IASTFunctionDeclarator in declarator hierarchy
|
||||
while (!(getterDeclarator instanceof IASTFunctionDeclarator)) {
|
||||
getterDeclarator = getterDeclarator.getNestedDeclarator();
|
||||
}
|
||||
getter.setDeclarator((IASTFunctionDeclarator) getterDeclarator);
|
||||
getter.setBody(getGetterBody(fieldName));
|
||||
getter.setBody(getGetterBody());
|
||||
return getter;
|
||||
}
|
||||
|
||||
private static CPPASTCompoundStatement getGetterBody(IASTName fieldName) {
|
||||
private CPPASTCompoundStatement getGetterBody() {
|
||||
CPPASTCompoundStatement compound = new CPPASTCompoundStatement();
|
||||
CPPASTReturnStatement returnStatement = new CPPASTReturnStatement();
|
||||
CPPASTIdExpression idExpr = new CPPASTIdExpression();
|
||||
|
@ -70,36 +83,38 @@ public class FunctionFactory {
|
|||
return compound;
|
||||
}
|
||||
|
||||
private static IASTDeclarator getGetterDeclarator(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
|
||||
private IASTDeclarator getGetterDeclarator(ICPPASTQualifiedName qualifiedName) {
|
||||
CPPASTName getterName = new CPPASTName();
|
||||
getterName.setName(GetterSetterNameGenerator.generateGetterName(fieldName).toCharArray());
|
||||
|
||||
// copy declarator hierarchy
|
||||
// Copy declarator hierarchy
|
||||
IASTDeclarator topDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations);
|
||||
|
||||
// find the innermost declarator in hierarchy
|
||||
// Find the innermost declarator in hierarchy
|
||||
IASTDeclarator innermost = topDeclarator;
|
||||
while (innermost.getNestedDeclarator() != null) {
|
||||
innermost = innermost.getNestedDeclarator();
|
||||
}
|
||||
|
||||
// create a new innermost function declarator basing on the field declarator
|
||||
// Create a new innermost function declarator based on the field declarator
|
||||
CPPASTFunctionDeclarator functionDeclarator = new CPPASTFunctionDeclarator();
|
||||
functionDeclarator.setConst(true);
|
||||
if (name != null) {
|
||||
name.addName(getterName);
|
||||
functionDeclarator.setName(name);
|
||||
if (qualifiedName != null) {
|
||||
qualifiedName.addName(getterName);
|
||||
functionDeclarator.setName(qualifiedName);
|
||||
} else {
|
||||
functionDeclarator.setName(getterName);
|
||||
}
|
||||
for (IASTPointerOperator pointer : innermost.getPointerOperators()){
|
||||
functionDeclarator.addPointerOperator(pointer.copy(CopyStyle.withLocations));
|
||||
}
|
||||
if (passByReference) {
|
||||
functionDeclarator.addPointerOperator(new CPPASTReferenceOperator(false));
|
||||
}
|
||||
|
||||
// replace innermost with functionDeclarator and return the whole declarator tree
|
||||
// Replace the innermost with functionDeclarator and return the whole declarator tree
|
||||
if (innermost == topDeclarator) {
|
||||
// no tree
|
||||
// No tree
|
||||
return functionDeclarator;
|
||||
} else {
|
||||
IASTDeclarator parent = (IASTDeclarator) innermost.getParent();
|
||||
|
@ -108,16 +123,15 @@ public class FunctionFactory {
|
|||
}
|
||||
}
|
||||
|
||||
public static IASTFunctionDefinition createSetterDefinition(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
|
||||
public IASTFunctionDefinition createSetterDefinition(ICPPASTQualifiedName qualifiedName) {
|
||||
IASTFunctionDefinition setter = new CPPASTFunctionDefinition();
|
||||
setter.setDeclSpecifier(getVoidDeclSpec());
|
||||
setter.setDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, name));
|
||||
setter.setBody(getSetterBody(fieldDeclaration));
|
||||
setter.setDeclarator(getSetterDeclarator(qualifiedName));
|
||||
setter.setBody(getSetterBody());
|
||||
return setter;
|
||||
}
|
||||
|
||||
private static CPPASTCompoundStatement getSetterBody(IASTSimpleDeclaration fieldDeclaration) {
|
||||
private CPPASTCompoundStatement getSetterBody() {
|
||||
CPPASTCompoundStatement compound = new CPPASTCompoundStatement();
|
||||
CPPASTExpressionStatement exprStmt = new CPPASTExpressionStatement();
|
||||
CPPASTBinaryExpression binExpr = new CPPASTBinaryExpression();
|
||||
|
@ -126,7 +140,7 @@ public class FunctionFactory {
|
|||
innerDeclarator = innerDeclarator.getNestedDeclarator();
|
||||
}
|
||||
IASTName fieldName = innerDeclarator.getName();
|
||||
CPPASTName parameterName = getSetterParameterName(fieldName);
|
||||
CPPASTName parameterName = getSetterParameterName();
|
||||
if (Arrays.equals(fieldName.getSimpleID(), parameterName.getSimpleID())) {
|
||||
CPPASTFieldReference fieldRef = new CPPASTFieldReference();
|
||||
CPPASTLiteralExpression litExpr = new CPPASTLiteralExpression();
|
||||
|
@ -147,28 +161,29 @@ public class FunctionFactory {
|
|||
return compound;
|
||||
}
|
||||
|
||||
private static CPPASTFunctionDeclarator getSetterDeclarator(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
|
||||
private CPPASTFunctionDeclarator getSetterDeclarator(ICPPASTQualifiedName qualifiedName) {
|
||||
CPPASTName setterName = new CPPASTName();
|
||||
setterName.setName(GetterSetterNameGenerator.generateSetterName(fieldName).toCharArray());
|
||||
CPPASTFunctionDeclarator declarator = new CPPASTFunctionDeclarator();
|
||||
if (name != null) {
|
||||
name.addName(setterName);
|
||||
declarator.setName(name);
|
||||
if (qualifiedName != null) {
|
||||
qualifiedName.addName(setterName);
|
||||
declarator.setName(qualifiedName);
|
||||
} else {
|
||||
declarator.setName(setterName);
|
||||
}
|
||||
CPPASTParameterDeclaration parameterDeclaration = new CPPASTParameterDeclaration();
|
||||
IASTDeclarator parameterDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations);
|
||||
parameterDeclarator.setName(getSetterParameterName(fieldName));
|
||||
parameterDeclarator.setName(getSetterParameterName());
|
||||
if (passByReference) {
|
||||
parameterDeclarator.addPointerOperator(new CPPASTReferenceOperator(false));
|
||||
}
|
||||
parameterDeclaration.setDeclarator(parameterDeclarator);
|
||||
parameterDeclaration.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy(
|
||||
CopyStyle.withLocations));
|
||||
parameterDeclaration.setDeclSpecifier(getParamOrReturnDeclSpecifier());
|
||||
declarator.addParameterDeclaration(parameterDeclaration.copy(CopyStyle.withLocations));
|
||||
return declarator;
|
||||
}
|
||||
|
||||
private static CPPASTName getSetterParameterName(IASTName fieldName) {
|
||||
private CPPASTName getSetterParameterName() {
|
||||
String parameterName = GetterSetterNameGenerator.generateSetterParameterName(fieldName);
|
||||
return new CPPASTName(parameterName.toCharArray());
|
||||
}
|
||||
|
@ -179,25 +194,25 @@ public class FunctionFactory {
|
|||
return declSpecifier;
|
||||
}
|
||||
|
||||
public static IASTSimpleDeclaration createGetterDeclaration(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration) {
|
||||
public IASTSimpleDeclaration createGetterDeclaration() {
|
||||
IASTSimpleDeclaration getter = new CPPASTSimpleDeclaration();
|
||||
IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier();
|
||||
getter.setDeclSpecifier(declSpec.copy(CopyStyle.withLocations));
|
||||
// TODO(sprigogin): Implement return by reference
|
||||
// IType type = CPPVisitor.createType(declSpec);
|
||||
// if (TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit())) {
|
||||
// declSpec.s
|
||||
// }
|
||||
getter.addDeclarator(getGetterDeclarator(fieldName, fieldDeclaration, null));
|
||||
getter.setDeclSpecifier(getParamOrReturnDeclSpecifier());
|
||||
getter.addDeclarator(getGetterDeclarator(null));
|
||||
return getter;
|
||||
}
|
||||
|
||||
public static IASTSimpleDeclaration createSetterDeclaration(IASTName fieldName,
|
||||
IASTSimpleDeclaration fieldDeclaration) {
|
||||
private IASTDeclSpecifier getParamOrReturnDeclSpecifier() {
|
||||
IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations);
|
||||
if (passByReference) {
|
||||
declSpec.setConst(true);
|
||||
}
|
||||
return declSpec;
|
||||
}
|
||||
|
||||
public IASTSimpleDeclaration createSetterDeclaration() {
|
||||
IASTSimpleDeclaration setter = new CPPASTSimpleDeclaration();
|
||||
setter.setDeclSpecifier(getVoidDeclSpec());
|
||||
setter.addDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, null));
|
||||
setter.addDeclarator(getSetterDeclarator(null));
|
||||
return setter;
|
||||
}
|
||||
}
|
|
@ -31,14 +31,14 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
|
|||
|
||||
private IASTSimpleDeclaration functionDeclaration;
|
||||
private AccessorKind kind;
|
||||
private IASTName fieldName;
|
||||
private IASTSimpleDeclaration fieldDeclaration;
|
||||
private GetterSetterFactory getterSetterFactory;
|
||||
|
||||
public GetterSetterInsertEditProvider(IASTName fieldName, IASTSimpleDeclaration fieldDeclaration,
|
||||
AccessorKind kind) {
|
||||
this.kind = kind;
|
||||
this.fieldName = fieldName;
|
||||
this.fieldDeclaration = fieldDeclaration;
|
||||
this.getterSetterFactory = new GetterSetterFactory(fieldName, fieldDeclaration);
|
||||
|
||||
createFunctionDeclaration();
|
||||
}
|
||||
|
@ -46,10 +46,10 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
|
|||
public void createFunctionDeclaration() {
|
||||
switch (this.kind) {
|
||||
case GETTER:
|
||||
this.functionDeclaration = FunctionFactory.createGetterDeclaration(fieldName, fieldDeclaration);
|
||||
this.functionDeclaration = getterSetterFactory.createGetterDeclaration();
|
||||
break;
|
||||
case SETTER:
|
||||
this.functionDeclaration = FunctionFactory.createSetterDeclaration(fieldName, fieldDeclaration);
|
||||
this.functionDeclaration = getterSetterFactory.createSetterDeclaration();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -67,23 +67,23 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
|
|||
IASTFunctionDefinition definition = null;
|
||||
ICPPASTQualifiedName qname;
|
||||
if (qualifedName) {
|
||||
qname = getClassname();
|
||||
qname = getClassName();
|
||||
} else {
|
||||
qname = null;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case GETTER:
|
||||
definition = FunctionFactory.createGetterDefinition(fieldName, fieldDeclaration, qname);
|
||||
definition = getterSetterFactory.createGetterDefinition(qname);
|
||||
break;
|
||||
case SETTER:
|
||||
definition = FunctionFactory.createSetterDefinition(fieldName, fieldDeclaration, qname);
|
||||
definition = getterSetterFactory.createSetterDefinition(qname);
|
||||
break;
|
||||
}
|
||||
return definition;
|
||||
}
|
||||
|
||||
private ICPPASTQualifiedName getClassname() {
|
||||
private ICPPASTQualifiedName getClassName() {
|
||||
IASTNode node = fieldDeclaration.getParent();
|
||||
while (!(node instanceof IASTCompositeTypeSpecifier)) {
|
||||
node = node.getParent();
|
||||
|
|
|
@ -84,6 +84,7 @@ public class CReconciler extends MonoReconciler {
|
|||
/*
|
||||
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(ISchedulingRule rule) {
|
||||
return rule == this;
|
||||
}
|
||||
|
@ -91,6 +92,7 @@ public class CReconciler extends MonoReconciler {
|
|||
/*
|
||||
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
|
||||
*/
|
||||
@Override
|
||||
public boolean isConflicting(ISchedulingRule rule) {
|
||||
return rule == this;
|
||||
}
|
||||
|
@ -104,26 +106,31 @@ public class CReconciler extends MonoReconciler {
|
|||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partActivated(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partBroughtToTop(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partClosed(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partDeactivated(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partHidden(IWorkbenchPartReference partRef) {
|
||||
if (partRef.getPart(false) == fTextEditor) {
|
||||
setEditorActive(false);
|
||||
|
@ -132,16 +139,19 @@ public class CReconciler extends MonoReconciler {
|
|||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partInputChanged(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partOpened(IWorkbenchPartReference partRef) {
|
||||
}
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
@Override
|
||||
public void partVisible(IWorkbenchPartReference partRef) {
|
||||
if (partRef.getPart(false) == fTextEditor) {
|
||||
CReconciler.this.scheduleReconciling();
|
||||
|
@ -192,6 +202,7 @@ public class CReconciler extends MonoReconciler {
|
|||
/*
|
||||
* @see org.eclipse.cdt.core.model.IElementChangedListener#elementChanged(org.eclipse.cdt.core.model.ElementChangedEvent)
|
||||
*/
|
||||
@Override
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
if (event.getType() == ElementChangedEvent.POST_CHANGE) {
|
||||
if (isRelevantDelta(event.getDelta())) {
|
||||
|
@ -209,10 +220,7 @@ public class CReconciler extends MonoReconciler {
|
|||
if ((flags & ICElementDelta.F_CONTENT) != 0) {
|
||||
if (!fIsReconciling && isRelevantElement(delta.getElement())) {
|
||||
// mark model changed, but don't update immediately
|
||||
fIndexerListener.ignoreChanges(false);
|
||||
setCModelChanged(true);
|
||||
} else if (delta.getElement() instanceof ITranslationUnit) {
|
||||
fIndexerListener.ignoreChanges(true);
|
||||
}
|
||||
}
|
||||
if ((flags & (
|
||||
|
@ -237,11 +245,11 @@ public class CReconciler extends MonoReconciler {
|
|||
|
||||
private class IndexerListener implements IIndexerStateListener, IIndexChangeListener {
|
||||
private boolean fIndexChanged;
|
||||
private boolean fIgnoreChanges;
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.index.IIndexerStateListener#indexChanged(org.eclipse.cdt.core.index.IIndexerStateEvent)
|
||||
*/
|
||||
@Override
|
||||
public void indexChanged(IIndexerStateEvent event) {
|
||||
if (event.indexerIsIdle()) {
|
||||
if (fIndexChanged || hasCModelChanged()) {
|
||||
|
@ -252,27 +260,20 @@ public class CReconciler extends MonoReconciler {
|
|||
setCModelChanged(true);
|
||||
}
|
||||
}
|
||||
fIgnoreChanges= false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ignoreChanges(boolean ignore) {
|
||||
fIgnoreChanges= ignore;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.index.IIndexChangeListener#indexChanged(org.eclipse.cdt.core.index.IIndexChangeEvent)
|
||||
*/
|
||||
@Override
|
||||
public void indexChanged(IIndexChangeEvent event) {
|
||||
if (!fIndexChanged && isRelevantProject(event.getAffectedProject())) {
|
||||
if (!fIgnoreChanges || event.isCleared() || event.isReloaded() || event.hasNewFile()) {
|
||||
fIndexChanged= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The reconciler's editor */
|
||||
private ITextEditor fTextEditor;
|
||||
/** The part listener */
|
||||
|
@ -328,6 +329,7 @@ public class CReconciler extends MonoReconciler {
|
|||
CCorePlugin.getIndexManager().addIndexChangeListener(fIndexerListener);
|
||||
|
||||
fTriggerReconcilerJob= new SingletonJob("Trigger Reconciler", new Runnable() { //$NON-NLS-1$
|
||||
@Override
|
||||
public void run() {
|
||||
forceReconciling();
|
||||
}});
|
||||
|
|
|
@ -100,9 +100,11 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
|
||||
protected static class SingletonRule implements ISchedulingRule {
|
||||
public static final ISchedulingRule INSTANCE = new SingletonRule();
|
||||
@Override
|
||||
public boolean contains(ISchedulingRule rule) {
|
||||
return rule == this;
|
||||
}
|
||||
@Override
|
||||
public boolean isConflicting(ISchedulingRule rule) {
|
||||
return rule == this;
|
||||
}
|
||||
|
@ -132,6 +134,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
/*
|
||||
* @see org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable#runOnAST(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit)
|
||||
*/
|
||||
@Override
|
||||
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
|
||||
if (ast != null) {
|
||||
try {
|
||||
|
@ -637,12 +640,8 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
|
||||
String[] sourceLines= Strings.convertIntoLines(source);
|
||||
String firstLine= sourceLines[0];
|
||||
if (firstLine.length() > 0 && !Character.isWhitespace(firstLine.charAt(0)))
|
||||
sourceLines[0]= ""; //$NON-NLS-1$
|
||||
Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth());
|
||||
|
||||
if (!Character.isWhitespace(firstLine.charAt(0)))
|
||||
sourceLines[0]= firstLine;
|
||||
boolean ignoreFirstLine= firstLine.length() > 0 && !Character.isWhitespace(firstLine.charAt(0));
|
||||
Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth(), !ignoreFirstLine);
|
||||
|
||||
source = Strings.concatenate(sourceLines, delim);
|
||||
return source;
|
||||
|
@ -797,6 +796,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
@Override
|
||||
public IInformationControlCreator getHoverControlCreator() {
|
||||
return new IInformationControlCreator() {
|
||||
@Override
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
IEditorPart editor= getEditor();
|
||||
int orientation= SWT.NONE;
|
||||
|
@ -814,6 +814,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
|
|||
@Override
|
||||
public IInformationControlCreator getInformationPresenterControlCreator() {
|
||||
return new IInformationControlCreator() {
|
||||
@Override
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
IEditorPart editor= getEditor();
|
||||
int orientation= SWT.NONE;
|
||||
|
|
|
@ -61,6 +61,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
|
|||
|
||||
private String fErrorMessage;
|
||||
|
||||
@Override
|
||||
public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) {
|
||||
List<ICompletionProposal> proposals= Collections.emptyList();
|
||||
fErrorMessage= null;
|
||||
|
@ -81,17 +82,21 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
|
|||
return proposals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return fErrorMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionEnded() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionStarted() {
|
||||
}
|
||||
|
||||
|
@ -257,6 +262,9 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
|
|||
final int prefixLength = namePrefix.length();
|
||||
final IProject project= tu.getCProject().getProject();
|
||||
File[] files= fileDir.listFiles();
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(namePrefix);
|
||||
for (File file : files) {
|
||||
final String name= file.getName();
|
||||
|
@ -311,6 +319,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
|
|||
final IProject project= tu.getCProject().getProject();
|
||||
parent.accept(new IResourceProxyVisitor() {
|
||||
boolean fFirstVisit= true;
|
||||
@Override
|
||||
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||
final int type= proxy.getType();
|
||||
final String name= proxy.getName();
|
||||
|
|
|
@ -192,7 +192,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
|||
// editor.setAction("AddDelegateMethods", fAddDelegateMethods); //$NON-NLS-1$
|
||||
//
|
||||
// fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(editor);
|
||||
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS);
|
||||
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS);
|
||||
// editor.setAction("AddUnimplementedConstructors", fAddUnimplementedConstructors); //$NON-NLS-1$
|
||||
//
|
||||
// fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(editor);
|
||||
|
@ -277,7 +277,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
|||
// fAddDelegateMethods.setActionDefinitionId(ICEditorActionDefinitionIds.CREATE_DELEGATE_METHODS);
|
||||
//
|
||||
// fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(site);
|
||||
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS);
|
||||
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS);
|
||||
//
|
||||
// fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(site);
|
||||
// fGenerateConstructorUsingFields.setActionDefinitionId(ICEditorActionDefinitionIds.GENERATE_CONSTRUCTOR_USING_FIELDS);
|
||||
|
|
|
@ -80,7 +80,7 @@ public abstract class AbstractErrorParserBlock extends AbstractCOptionPage {
|
|||
@Deprecated
|
||||
public AbstractErrorParserBlock(Preferences prefs) {
|
||||
this();
|
||||
// usingDeprecatedContructor = true;
|
||||
// usingDeprecatedConstructor = true;
|
||||
fPrefs = prefs;
|
||||
}
|
||||
|
||||
|
|
11
dsf/org.eclipse.cdt.dsf/.settings/.api_filters
Normal file
11
dsf/org.eclipse.cdt.dsf/.settings/.api_filters
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<component id="org.eclipse.cdt.dsf" version="2">
|
||||
<resource path="src/org/eclipse/cdt/dsf/concurrent/Transaction.java" type="org.eclipse.cdt.dsf.concurrent.Transaction">
|
||||
<filter comment="Utility is not in common use. I changed erasure type for argument, but at worse this should only cause a warning." id="420679712">
|
||||
<message_arguments>
|
||||
<message_argument value="org.eclipse.cdt.dsf.concurrent.Transaction.validate(ICache<?>[])"/>
|
||||
<message_argument value="T"/>
|
||||
</message_arguments>
|
||||
</filter>
|
||||
</resource>
|
||||
</component>
|
|
@ -155,6 +155,27 @@ public abstract class AbstractCache<V> implements ICache<V> {
|
|||
}
|
||||
}
|
||||
|
||||
private void completeWaitingRms() {
|
||||
Object waiting = null;
|
||||
synchronized(this) {
|
||||
waiting = fWaitingList;
|
||||
fWaitingList = null;
|
||||
}
|
||||
if (waiting != null) {
|
||||
if (waiting instanceof RequestMonitor) {
|
||||
completeWaitingRm((RequestMonitor)waiting);
|
||||
} else if (waiting instanceof RequestMonitor[]) {
|
||||
RequestMonitor[] waitingList = (RequestMonitor[])waiting;
|
||||
for (int i = 0; i < waitingList.length; i++) {
|
||||
if (waitingList[i] != null) {
|
||||
completeWaitingRm(waitingList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
waiting = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void completeWaitingRm(RequestMonitor rm) {
|
||||
rm.setStatus(fStatus);
|
||||
rm.removeCancelListener(fRequestCanceledListener);
|
||||
|
@ -300,23 +321,33 @@ public abstract class AbstractCache<V> implements ICache<V> {
|
|||
fStatus = status;
|
||||
fValid = true;
|
||||
|
||||
Object waiting = null;
|
||||
synchronized(this) {
|
||||
waiting = fWaitingList;
|
||||
fWaitingList = null;
|
||||
}
|
||||
if (waiting != null) {
|
||||
if (waiting instanceof RequestMonitor) {
|
||||
completeWaitingRm((RequestMonitor)waiting);
|
||||
} else if (waiting instanceof RequestMonitor[]) {
|
||||
RequestMonitor[] waitingList = (RequestMonitor[])waiting;
|
||||
for (int i = 0; i < waitingList.length; i++) {
|
||||
if (waitingList[i] != null) {
|
||||
completeWaitingRm(waitingList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
waiting = null;
|
||||
completeWaitingRms();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the set and reset operations in one step This allows the cache to
|
||||
* remain in invalid state, but to notify any waiting listeners that the state of
|
||||
* the cache has changed.
|
||||
*
|
||||
* @param data
|
||||
* The data that should be returned to any clients waiting for
|
||||
* cache data and for clients requesting data until the cache is
|
||||
* invalidated.
|
||||
* @status The status that should be returned to any clients waiting for
|
||||
* cache data and for clients requesting data until the cache is
|
||||
* invalidated
|
||||
*
|
||||
* @see #reset(Object, IStatus)
|
||||
* @since 2.3
|
||||
*/
|
||||
protected void setAndReset(V data, IStatus status) {
|
||||
assert fExecutor.getDsfExecutor().isInExecutorThread();
|
||||
|
||||
fData = data;
|
||||
fStatus = status;
|
||||
fValid = false;
|
||||
|
||||
completeWaitingRms();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,8 +107,7 @@ abstract public class RangeCache<V> {
|
|||
protected List<V> process() throws InvalidCacheException, CoreException {
|
||||
clearCanceledRequests();
|
||||
|
||||
List<ICache<?>> transactionRequests = getRequests(fOffset, fCount);
|
||||
|
||||
List<Request> transactionRequests = getRequests(fOffset, fCount);
|
||||
validate(transactionRequests);
|
||||
|
||||
return makeElementsListFromRequests(transactionRequests, fOffset, fCount);
|
||||
|
@ -156,7 +155,7 @@ abstract public class RangeCache<V> {
|
|||
public ICache<List<V>> getRange(final long offset, final int count) {
|
||||
assert fExecutor.getDsfExecutor().isInExecutorThread();
|
||||
|
||||
List<ICache<?>> requests = getRequests(offset, count);
|
||||
List<Request> requests = getRequests(offset, count);
|
||||
|
||||
RequestCache<List<V>> range = new RequestCache<List<V>>(fExecutor) {
|
||||
@Override
|
||||
|
@ -232,8 +231,8 @@ abstract public class RangeCache<V> {
|
|||
}
|
||||
}
|
||||
|
||||
private List<ICache<?>> getRequests(long fOffset, int fCount) {
|
||||
List<ICache<?>> requests = new ArrayList<ICache<?>>(1);
|
||||
private List<Request> getRequests(long fOffset, int fCount) {
|
||||
List<Request> requests = new ArrayList<Request>(1);
|
||||
|
||||
// Create a new request for the data to retrieve.
|
||||
Request current = new Request(fOffset, fCount);
|
||||
|
@ -252,7 +251,7 @@ abstract public class RangeCache<V> {
|
|||
// Adjust the beginning of the requested range of data. If there
|
||||
// is already an overlapping range in front of the requested range,
|
||||
// then use it.
|
||||
private Request adjustRequestHead(Request request, List<ICache<?>> transactionRequests, long offset, int count) {
|
||||
private Request adjustRequestHead(Request request, List<Request> transactionRequests, long offset, int count) {
|
||||
SortedSet<Request> headRequests = fRequests.headSet(request);
|
||||
if (!headRequests.isEmpty()) {
|
||||
Request headRequest = headRequests.last();
|
||||
|
@ -276,7 +275,7 @@ abstract public class RangeCache<V> {
|
|||
* @param transactionRequests
|
||||
* @return
|
||||
*/
|
||||
private Request adjustRequestTail(Request current, List<ICache<?>> transactionRequests, long offset, int count) {
|
||||
private Request adjustRequestTail(Request current, List<Request> transactionRequests, long offset, int count) {
|
||||
// Create a duplicate of the tailSet, in order to avoid a concurrent modification exception.
|
||||
List<Request> tailSet = new ArrayList<Request>(fRequests.tailSet(current));
|
||||
|
||||
|
@ -313,14 +312,13 @@ abstract public class RangeCache<V> {
|
|||
return current;
|
||||
}
|
||||
|
||||
private List<V> makeElementsListFromRequests(List<ICache<?>> requests, long offset, int count) {
|
||||
private List<V> makeElementsListFromRequests(List<Request> requests, long offset, int count) {
|
||||
List<V> retVal = new ArrayList<V>(count);
|
||||
long index = offset;
|
||||
long end = offset + count;
|
||||
int requestIdx = 0;
|
||||
while (index < end ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Request request = (Request)requests.get(requestIdx);
|
||||
Request request = requests.get(requestIdx);
|
||||
if (index < request.fOffset + request.fCount) {
|
||||
retVal.add( request.getData().get((int)(index - request.fOffset)) );
|
||||
index ++;
|
||||
|
|
|
@ -94,4 +94,13 @@ public abstract class RequestCache<V> extends AbstractCache<V> {
|
|||
}
|
||||
super.set(data, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset() {
|
||||
if (fRm != null) {
|
||||
fRm.cancel();
|
||||
fRm = null;
|
||||
}
|
||||
super.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,8 +70,10 @@ public abstract class Transaction<V> {
|
|||
* logic once the cache object has been updated from the source.
|
||||
*
|
||||
* @return the cached data if it's valid, otherwise an exception is thrown
|
||||
* @throws InvalidCacheException
|
||||
* @throws CoreException
|
||||
* @throws Transaction.InvalidCacheException Exception indicating that a
|
||||
* cache is not valid and transaction will need to be rescheduled.
|
||||
* @throws CoreException Exception indicating that one of the caches is
|
||||
* in error state and transaction cannot be processed.
|
||||
*/
|
||||
abstract protected V process() throws InvalidCacheException, CoreException;
|
||||
|
||||
|
@ -149,7 +151,7 @@ public abstract class Transaction<V> {
|
|||
* See {@link #validate(RequestCache)}. This variant simply validates
|
||||
* multiple cache objects.
|
||||
*/
|
||||
public void validate(ICache<?> ... caches) throws InvalidCacheException, CoreException {
|
||||
public <T> void validate(ICache<?> ... caches) throws InvalidCacheException, CoreException {
|
||||
validate(Arrays.asList(caches));
|
||||
}
|
||||
|
||||
|
@ -157,11 +159,12 @@ public abstract class Transaction<V> {
|
|||
* See {@link #validate(RequestCache)}. This variant simply validates
|
||||
* multiple cache objects.
|
||||
*/
|
||||
public void validate(Iterable<ICache<?>> caches) throws InvalidCacheException, CoreException {
|
||||
public void validate(@SuppressWarnings("rawtypes") Iterable caches) throws InvalidCacheException, CoreException {
|
||||
// Check if any of the caches have errors:
|
||||
boolean allValid = true;
|
||||
|
||||
for (ICache<?> cache : caches) {
|
||||
for (Object cacheObj : caches) {
|
||||
ICache<?> cache = (ICache<?>)cacheObj;
|
||||
if (cache.isValid()) {
|
||||
if (!cache.getStatus().isOK()) {
|
||||
throw new CoreException(cache.getStatus());
|
||||
|
@ -181,7 +184,8 @@ public abstract class Transaction<V> {
|
|||
}
|
||||
};
|
||||
int count = 0;
|
||||
for (ICache<?> cache : caches) {
|
||||
for (Object cacheObj : caches) {
|
||||
ICache<?> cache = (ICache<?>)cacheObj;
|
||||
if (!cache.isValid()) {
|
||||
cache.update(countringRm);
|
||||
count++;
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Wind River 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
|
||||
*
|
||||
* Contributors:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
//#ifdef exercises
|
||||
package org.eclipse.cdt.examples.dsf.dataviewer;
|
||||
//#else
|
||||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||
import org.eclipse.cdt.dsf.concurrent.ICache;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Transaction;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
* A data generator which performs a sum computation on data retrieved from a
|
||||
* number of other data generators. The data retrieval from other generators
|
||||
* is performed using ACPM caches and the result is calculated once all caches
|
||||
* are valid.
|
||||
* <p>
|
||||
* Unlike {@link AsyncSumDataGenerator}, this data generator listens to events
|
||||
* from the individual the data providers. Theve events are used to
|
||||
* invalidate caches to make sure that they don't return incorrect data. This
|
||||
* generator also sends out events to its clients to notify them to update, or
|
||||
* invalidate their caches.
|
||||
* </p>
|
||||
*/
|
||||
public class ACPMSumDataGenerator
|
||||
implements IDataGenerator, IDataGenerator.Listener
|
||||
{
|
||||
|
||||
/**
|
||||
* DSF executor used to serialize data access within this data generator.
|
||||
*/
|
||||
final private DsfExecutor fExecutor;
|
||||
|
||||
/**
|
||||
* Data generators to retrieve original data to perform calculations on.
|
||||
* The generators are accessed through the cache manager wrappers.
|
||||
*/
|
||||
final private DataGeneratorCacheManager[] fDataGeneratorCMs;
|
||||
|
||||
/**
|
||||
* List of listeners for this data generator.
|
||||
*/
|
||||
final private List<Listener> fListeners = new LinkedList<Listener>();
|
||||
|
||||
public ACPMSumDataGenerator(DsfExecutor executor,
|
||||
IDataGenerator[] generators)
|
||||
{
|
||||
fExecutor = executor;
|
||||
|
||||
// Create wrappers for data generators and add ourselves as listener
|
||||
// to their events.
|
||||
fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
|
||||
ImmediateInDsfExecutor immediateExecutor =
|
||||
new ImmediateInDsfExecutor(fExecutor);
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
fDataGeneratorCMs[i] = new DataGeneratorCacheManager(
|
||||
immediateExecutor, generators[i]);
|
||||
generators[i].addListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void getCount(final DataRequestMonitor<Integer> rm) {
|
||||
// Artificially delay the retrieval of the sum data to simulate
|
||||
// real processing time.
|
||||
fExecutor.schedule( new Runnable() {
|
||||
public void run() {
|
||||
// Create the transaction here to put all the ugly
|
||||
// code in one place.
|
||||
new Transaction<Integer>() {
|
||||
@Override
|
||||
protected Integer process()
|
||||
throws Transaction.InvalidCacheException,
|
||||
CoreException
|
||||
{
|
||||
return processCount(this);
|
||||
}
|
||||
}.request(rm);
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the calculation to get the max count for the given transaction.
|
||||
* @param transaction The ACPM transaction to use for calculation.
|
||||
* @return Calculated count.
|
||||
* @throws Transaction.InvalidCacheException {@link Transaction#process}
|
||||
* @throws CoreException See {@link Transaction#process}
|
||||
*/
|
||||
private Integer processCount(Transaction<Integer> transaction)
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
// Assemble all needed count caches into a collection.
|
||||
List<ICache<Integer>> countCaches =
|
||||
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
|
||||
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
|
||||
countCaches.add(dataGeneratorCM.getCount());
|
||||
}
|
||||
// Validate all count caches at once. This executes needed requests
|
||||
// in parallel.
|
||||
transaction.validate(countCaches);
|
||||
|
||||
// Calculate the max value and return.
|
||||
int maxCount = 0;
|
||||
for (ICache<Integer> countCache : countCaches) {
|
||||
maxCount = Math.max(maxCount, countCache.getData());
|
||||
}
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
public void getValue(final int index, final DataRequestMonitor<Integer> rm)
|
||||
{
|
||||
// Add a processing delay.
|
||||
fExecutor.schedule( new Runnable() {
|
||||
public void run() {
|
||||
new Transaction<Integer>() {
|
||||
@Override
|
||||
protected Integer process()
|
||||
throws Transaction.InvalidCacheException,
|
||||
CoreException
|
||||
{
|
||||
return processValue(this, index);
|
||||
}
|
||||
}.request(rm);
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the calculation to get the sum of values at given index.
|
||||
* @param transaction The ACPM transaction to use for calculation.
|
||||
* @param index Index of value to calculate.
|
||||
* @return Calculated value.
|
||||
* @throws Transaction.InvalidCacheException {@link Transaction#process}
|
||||
* @throws CoreException See {@link Transaction#process}
|
||||
*/
|
||||
private Integer processValue(Transaction<Integer> transaction, int index)
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
List<ICache<Integer>> valueCaches =
|
||||
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
|
||||
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
|
||||
valueCaches.add(dataGeneratorCM.getValue(index));
|
||||
}
|
||||
// Validate all value caches at once. This executes needed requests
|
||||
// in parallel.
|
||||
transaction.validate(valueCaches);
|
||||
|
||||
int sum = 0;
|
||||
for (ICache<Integer> valueCache : valueCaches) {
|
||||
sum += valueCache.getData();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public void shutdown(final RequestMonitor rm) {
|
||||
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
|
||||
dataGeneratorCM.getDataGenerator().removeListener(this);
|
||||
dataGeneratorCM.dispose();
|
||||
rm.done();
|
||||
}
|
||||
rm.done();
|
||||
}
|
||||
|
||||
public void addListener(final Listener listener) {
|
||||
// Must access fListeners on executor thread.
|
||||
try {
|
||||
fExecutor.execute( new DsfRunnable() {
|
||||
public void run() {
|
||||
fListeners.add(listener);
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {}
|
||||
}
|
||||
|
||||
public void removeListener(final Listener listener) {
|
||||
// Must access fListeners on executor thread.
|
||||
try {
|
||||
fExecutor.execute( new DsfRunnable() {
|
||||
public void run() {
|
||||
fListeners.remove(listener);
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {}
|
||||
}
|
||||
|
||||
public void countChanged() {
|
||||
// Must access fListeners on executor thread.
|
||||
try {
|
||||
fExecutor.execute( new DsfRunnable() {
|
||||
public void run() {
|
||||
for (Listener listener : fListeners) {
|
||||
listener.countChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {}
|
||||
}
|
||||
|
||||
public void valuesChanged(final Set<Integer> changed) {
|
||||
// Must access fListeners on executor thread.
|
||||
try {
|
||||
fExecutor.execute( new DsfRunnable() {
|
||||
public void run() {
|
||||
for (Object listener : fListeners) {
|
||||
((Listener)listener).valuesChanged(changed);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,482 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Wind River 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
|
||||
*
|
||||
* Contributors:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
//#ifdef exercises
|
||||
package org.eclipse.cdt.examples.dsf.dataviewer;
|
||||
//#else
|
||||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ICache;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
|
||||
import org.eclipse.cdt.dsf.concurrent.Transaction;
|
||||
import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.jface.viewers.ILazyContentProvider;
|
||||
import org.eclipse.jface.viewers.TableViewer;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
|
||||
/**
|
||||
* Data viewer based on a table, which reads data from multiple data
|
||||
* providers using ACPM methods and performs a computation on the
|
||||
* retrieved data.
|
||||
* <p>
|
||||
* This example builds on the {@link AsyncSumDataViewer} example. It
|
||||
* demonstrates using ACPM to solve the data consistency problem when
|
||||
* retrieving data from multiple sources asynchronously.
|
||||
* </p>
|
||||
*/
|
||||
@ConfinedToDsfExecutor("fDisplayExecutor")
|
||||
public class ACPMSumDataViewer implements ILazyContentProvider
|
||||
{
|
||||
/** View update frequency interval. */
|
||||
final private static int UPDATE_INTERVAL = 10000;
|
||||
|
||||
/** Executor to use instead of Display.asyncExec(). **/
|
||||
@ThreadSafe
|
||||
final private DsfExecutor fDisplayExecutor;
|
||||
|
||||
/** Executor to use when retrieving data from data providers */
|
||||
@ThreadSafe
|
||||
final private ImmediateInDsfExecutor fDataExecutor;
|
||||
|
||||
// The viewer and generator that this content provider using.
|
||||
final private TableViewer fViewer;
|
||||
final private DataGeneratorCacheManager[] fDataGeneratorCMs;
|
||||
final private DataGeneratorCacheManager fSumGeneratorCM;
|
||||
|
||||
// Fields used in request cancellation logic.
|
||||
private List<ValueRequestMonitor> fItemDataRequestMonitors =
|
||||
new LinkedList<ValueRequestMonitor>();
|
||||
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
|
||||
private int fCancelCallsPending = 0;
|
||||
private Future<?> fRefreshFuture;
|
||||
|
||||
public ACPMSumDataViewer(TableViewer viewer,
|
||||
ImmediateInDsfExecutor dataExecutor, IDataGenerator[] generators,
|
||||
IDataGenerator sumGenerator)
|
||||
{
|
||||
fViewer = viewer;
|
||||
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
|
||||
fViewer.getTable().getDisplay());
|
||||
fDataExecutor = dataExecutor;
|
||||
|
||||
// Create wrappers for data generators. Don't need to register as
|
||||
// listeners to generator events because the cache managers ensure data
|
||||
// are already registered for them.
|
||||
fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
fDataGeneratorCMs[i] =
|
||||
new DataGeneratorCacheManager(fDataExecutor, generators[i]);
|
||||
}
|
||||
fSumGeneratorCM =
|
||||
new DataGeneratorCacheManager(fDataExecutor, sumGenerator);
|
||||
|
||||
// Schedule a task to refresh the viewer periodically.
|
||||
fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
queryItemCount();
|
||||
}
|
||||
},
|
||||
UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
// Cancel the periodic task of refreshing the view.
|
||||
fRefreshFuture.cancel(false);
|
||||
|
||||
// Need to dispose cache managers that were created in this class. This
|
||||
// needs to be done on the cache manager's thread.
|
||||
Query<Object> disposeCacheManagersQuery = new Query<Object>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<Object> rm) {
|
||||
fSumGeneratorCM.dispose();
|
||||
for (DataGeneratorCacheManager dataGeneratorCM :
|
||||
fDataGeneratorCMs)
|
||||
{
|
||||
dataGeneratorCM.dispose();
|
||||
}
|
||||
rm.setData(new Object());
|
||||
rm.done();
|
||||
}
|
||||
};
|
||||
fDataExecutor.execute(disposeCacheManagersQuery);
|
||||
try {
|
||||
disposeCacheManagersQuery.get();
|
||||
}
|
||||
catch (InterruptedException e) {}
|
||||
catch (ExecutionException e) {}
|
||||
|
||||
// Cancel any outstanding data requests.
|
||||
for (ValueRequestMonitor rm : fItemDataRequestMonitors) {
|
||||
rm.cancel();
|
||||
}
|
||||
fItemDataRequestMonitors.clear();
|
||||
}
|
||||
|
||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||
// Set the initial count to the viewer after the input is set.
|
||||
queryItemCount();
|
||||
}
|
||||
|
||||
public void updateElement(final int index) {
|
||||
// Calculate the visible index range.
|
||||
final int topIdx = fViewer.getTable().getTopIndex();
|
||||
final int botIdx = topIdx + getVisibleItemCount(topIdx);
|
||||
|
||||
// Request the item for the given index.
|
||||
queryValue(index);
|
||||
|
||||
// Invoke a cancel task with a delay. The delay allows multiple cancel
|
||||
// calls to be combined together improving performance of the viewer.
|
||||
fCancelCallsPending++;
|
||||
fDisplayExecutor.execute(
|
||||
new Runnable() { public void run() {
|
||||
cancelStaleRequests(topIdx, botIdx);
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of visible items based on the top item index and
|
||||
* table bounds.
|
||||
* @param top Index of top item.
|
||||
* @return calculated number of items in viewer
|
||||
*/
|
||||
private int getVisibleItemCount(int top) {
|
||||
Table table = fViewer.getTable();
|
||||
int itemCount = table.getItemCount();
|
||||
return Math.min(
|
||||
(table.getBounds().height / table.getItemHeight()) + 2,
|
||||
itemCount - top);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current count. When a new count is set to viewer, the viewer
|
||||
* will refresh all items as well.
|
||||
*/
|
||||
private void queryItemCount() {
|
||||
// Create the request monitor to collect the count. This request
|
||||
// monitor will be completed by the following transaction.
|
||||
final DataRequestMonitor<Integer> rm =
|
||||
new DataRequestMonitor<Integer>(fDisplayExecutor, null)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
setCountToViewer(getData());
|
||||
}
|
||||
@Override
|
||||
protected void handleRejectedExecutionException() {} // Shutting down, ignore.
|
||||
};
|
||||
|
||||
// Use a transaction, even with a single cache. This will ensure that
|
||||
// if the cache is reset during processing by an event. The request
|
||||
// for data will be re-issued.
|
||||
fDataExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
new Transaction<Integer>() {
|
||||
@Override
|
||||
protected Integer process()
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
return processCount(this);
|
||||
}
|
||||
}.request(rm);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the count retrieval from the sum data generator.
|
||||
* @param transaction The ACPM transaction to use for calculation.
|
||||
* @return Calculated count.
|
||||
* @throws Transaction.InvalidCacheException {@link Transaction#process}
|
||||
* @throws CoreException See {@link Transaction#process}
|
||||
*/
|
||||
private Integer processCount(Transaction<Integer> transaction)
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
ICache<Integer> countCache = fSumGeneratorCM.getCount();
|
||||
transaction.validate(countCache);
|
||||
return countCache.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the givne count to the viewer. This will cause the viewer will
|
||||
* refresh all items' data as well.
|
||||
* <p>Note: This method must be called in the display thread. </p>
|
||||
* @param count New count to set to viewer.
|
||||
*/
|
||||
private void setCountToViewer(int count) {
|
||||
if (!fViewer.getTable().isDisposed()) {
|
||||
fViewer.setItemCount(count);
|
||||
fViewer.getTable().clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current value for given index.
|
||||
*/
|
||||
private void queryValue(final int index) {
|
||||
// Create the request monitor to collect the value. This request
|
||||
// monitor will be completed by the following transaction.
|
||||
final ValueRequestMonitor rm = new ValueRequestMonitor(index) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
fItemDataRequestMonitors.remove(this);
|
||||
if (isSuccess()) {
|
||||
setValueToViewer(index, getData());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void handleRejectedExecutionException() {
|
||||
// Shutting down, ignore.
|
||||
}
|
||||
};
|
||||
|
||||
// Save the value request monitor, to cancel it if the view is
|
||||
// scrolled.
|
||||
fItemDataRequestMonitors.add(rm);
|
||||
|
||||
// Use a transaction, even with a single cache. This will ensure that
|
||||
// if the cache is reset during processing by an event. The request
|
||||
// for data will be re-issued.
|
||||
fDataExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
new Transaction<String>() {
|
||||
@Override
|
||||
protected String process()
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
return processValue(this, index);
|
||||
}
|
||||
}.request(rm);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the view value to the viewer.
|
||||
* <p>Note: This method must be called in the display thread. </p>
|
||||
* @param index Index of value to set.
|
||||
* @param value New value.
|
||||
*/
|
||||
private void setValueToViewer(int index, String value) {
|
||||
if (!fViewer.getTable().isDisposed()) {
|
||||
fViewer.replace(value, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the calculation compose the string with data provider values
|
||||
* and the sum. This implementation also validates the result.
|
||||
* @param transaction The ACPM transaction to use for calculation.
|
||||
* @param index Index of value to calculate.
|
||||
* @return Calculated value.
|
||||
* @throws Transaction.InvalidCacheException {@link Transaction#process}
|
||||
* @throws CoreException See {@link Transaction#process}
|
||||
*/
|
||||
private String processValue(Transaction<String> transaction, int index)
|
||||
throws Transaction.InvalidCacheException, CoreException
|
||||
{
|
||||
List<ICache<Integer>> valueCaches =
|
||||
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
|
||||
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
|
||||
valueCaches.add(dataGeneratorCM.getValue(index));
|
||||
}
|
||||
// Validate all value caches at once. This executes needed requests
|
||||
// in parallel.
|
||||
transaction.validate(valueCaches);
|
||||
|
||||
// TODO: evaluate sum generator cache in parallel with value caches.
|
||||
ICache<Integer> sumCache = fSumGeneratorCM.getValue(index);
|
||||
transaction.validate(sumCache);
|
||||
|
||||
// Compose the string with values, sum, and validation result.
|
||||
StringBuilder result = new StringBuilder();
|
||||
int calcSum = 0;
|
||||
for (ICache<Integer> valueCache : valueCaches) {
|
||||
if (result.length() != 0) result.append(" + ");
|
||||
result.append(valueCache.getData());
|
||||
calcSum += valueCache.getData();
|
||||
}
|
||||
result.append(" = ");
|
||||
result.append(sumCache.getData());
|
||||
if (calcSum != sumCache.getData()) {
|
||||
result.append(" !INCORRECT! ");
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated class for data item requests. This class holds the index
|
||||
* argument so it can be examined when canceling stale requests.
|
||||
*/
|
||||
private class ValueRequestMonitor extends DataRequestMonitor<String> {
|
||||
/** Index is used when canceling stale requests. */
|
||||
int fIndex;
|
||||
|
||||
ValueRequestMonitor(int index) {
|
||||
super(fDisplayExecutor, null);
|
||||
fIndex = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRejectedExecutionException() {
|
||||
// Shutting down, ignore.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any outstanding value requests for items which are no longer
|
||||
* visible in the viewer.
|
||||
*
|
||||
* @param topIdx Index of top visible item in viewer.
|
||||
* @param botIdx Index of bottom visible item in viewer.
|
||||
*/
|
||||
private void cancelStaleRequests(int topIdx, int botIdx) {
|
||||
// Decrement the count of outstanding cancel calls.
|
||||
fCancelCallsPending--;
|
||||
|
||||
// Must check again, in case disposed while re-dispatching.
|
||||
if (fDataGeneratorCMs == null || fViewer.getTable().isDisposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Go through the outstanding requests and cancel any that
|
||||
// are not visible anymore.
|
||||
for (Iterator<ValueRequestMonitor> itr =
|
||||
fItemDataRequestMonitors.iterator(); itr.hasNext();)
|
||||
{
|
||||
ValueRequestMonitor item = itr.next();
|
||||
if (item.fIndex < topIdx || item.fIndex > botIdx) {
|
||||
// Set the item to canceled status, so that the data provider
|
||||
// will ignore it.
|
||||
item.cancel();
|
||||
|
||||
// Add the item index to list of indexes that were canceled,
|
||||
// which will be sent to the table widget.
|
||||
fIndexesToCancel.add(item.fIndex);
|
||||
|
||||
// Remove the item from the outstanding cancel requests.
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
|
||||
Set<Integer> canceledIdxs = fIndexesToCancel;
|
||||
fIndexesToCancel = new HashSet<Integer>();
|
||||
|
||||
// Clear the indexes of the canceled request, so that the
|
||||
// viewer knows to request them again when needed.
|
||||
// Note: clearing using TableViewer.clear(int) seems very
|
||||
// inefficient, it's better to use Table.clear(int[]).
|
||||
int[] canceledIdxsArray = new int[canceledIdxs.size()];
|
||||
int i = 0;
|
||||
for (Integer index : canceledIdxs) {
|
||||
canceledIdxsArray[i++] = index;
|
||||
}
|
||||
fViewer.getTable().clear(canceledIdxsArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the example.
|
||||
* @param args Program arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Create the shell to hold the viewer.
|
||||
Display display = new Display();
|
||||
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||
shell.setLayout(new GridLayout());
|
||||
GridData data = new GridData(GridData.FILL_BOTH);
|
||||
shell.setLayoutData(data);
|
||||
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||
|
||||
// Create the table viewer.
|
||||
TableViewer tableViewer =
|
||||
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||
tableViewer.getControl().setLayoutData(data);
|
||||
|
||||
DsfExecutor executor = new DefaultDsfExecutor("Example executor");
|
||||
|
||||
// Create the data generator.
|
||||
final IDataGenerator[] generators = new IDataGenerator[5];
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
generators[i] = new DataGeneratorWithExecutor(executor);
|
||||
}
|
||||
final IDataGenerator sumGenerator =
|
||||
new ACPMSumDataGenerator(executor, generators);
|
||||
|
||||
// Create the content provider which will populate the viewer.
|
||||
ACPMSumDataViewer contentProvider = new ACPMSumDataViewer(
|
||||
tableViewer, new ImmediateInDsfExecutor(executor),
|
||||
generators, sumGenerator);
|
||||
tableViewer.setContentProvider(contentProvider);
|
||||
tableViewer.setInput(new Object());
|
||||
|
||||
// Open the shell and service the display dispatch loop until user
|
||||
// closes the shell.
|
||||
shell.open();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!display.readAndDispatch())
|
||||
display.sleep();
|
||||
}
|
||||
|
||||
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||
// using a query again in order to wait for its completion.
|
||||
Query<Object> shutdownQuery = new Query<Object>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<Object> rm) {
|
||||
CountingRequestMonitor crm = new CountingRequestMonitor(
|
||||
ImmediateExecutor.getInstance(), rm);
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
generators[i].shutdown(crm);
|
||||
}
|
||||
sumGenerator.shutdown(crm);
|
||||
crm.setDoneCount(generators.length);
|
||||
}
|
||||
};
|
||||
|
||||
executor.execute(shutdownQuery);
|
||||
try {
|
||||
shutdownQuery.get();
|
||||
} catch (Exception e) {}
|
||||
|
||||
// Shut down the display.
|
||||
font.dispose();
|
||||
display.dispose();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2009 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2011 Wind River 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
|
||||
|
@ -66,13 +66,15 @@ public class AsyncDataViewer
|
|||
final private IDataGenerator fDataGenerator;
|
||||
|
||||
// Fields used in request cancellation logic.
|
||||
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
|
||||
private List<ValueDataRequestMonitor> fItemDataRequestMonitors =
|
||||
new LinkedList<ValueDataRequestMonitor>();
|
||||
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
|
||||
private int fCancelCallsPending = 0;
|
||||
|
||||
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
|
||||
fViewer = viewer;
|
||||
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
|
||||
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
|
||||
fViewer.getTable().getDisplay());
|
||||
fDataGenerator = generator;
|
||||
fDataGenerator.addListener(this);
|
||||
}
|
||||
|
@ -104,10 +106,18 @@ public class AsyncDataViewer
|
|||
1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of visible items based on the top item index and
|
||||
* table bounds.
|
||||
* @param top Index of top item.
|
||||
* @return calculated number of items in viewer
|
||||
*/
|
||||
private int getVisibleItemCount(int top) {
|
||||
Table table = fViewer.getTable();
|
||||
int itemCount = table.getItemCount();
|
||||
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
|
||||
return Math.min(
|
||||
(table.getBounds().height / table.getItemHeight()) + 2,
|
||||
itemCount - top);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
|
@ -131,7 +141,10 @@ public class AsyncDataViewer
|
|||
}});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the up to date count. When a new count is set to viewer, the
|
||||
* viewer will refresh all items as well.
|
||||
*/
|
||||
private void queryItemCount() {
|
||||
// Request count from data provider. When the count is returned, we
|
||||
// have to re-dispatch into the display thread to avoid calling
|
||||
|
@ -150,13 +163,25 @@ public class AsyncDataViewer
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Dedicated class for data item requests. This class holds the index
|
||||
// argument so it can be examined when canceling stale requests.
|
||||
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
|
||||
/**
|
||||
* Retrieves value of an element at given index. When complete the value
|
||||
* is written to the viewer.
|
||||
* @param index Index of value to retrieve.
|
||||
*/
|
||||
private void queryValue(final int index) {
|
||||
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
|
||||
fItemDataRequestMonitors.add(rm);
|
||||
fDataGenerator.getValue(index, rm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated class for data item requests. This class holds the index
|
||||
* argument so it can be examined when canceling stale requests.
|
||||
*/
|
||||
private class ValueDataRequestMonitor extends DataRequestMonitor<Integer> {
|
||||
|
||||
/** Index is used when canceling stale requests. */
|
||||
int fIndex;
|
||||
|
@ -170,7 +195,8 @@ public class AsyncDataViewer
|
|||
protected void handleCompleted() {
|
||||
fItemDataRequestMonitors.remove(this);
|
||||
|
||||
// Check if the request completed successfully, otherwise ignore it.
|
||||
// Check if the request completed successfully, otherwise ignore
|
||||
// it.
|
||||
if (isSuccess()) {
|
||||
if (!fViewer.getTable().isDisposed()) {
|
||||
fViewer.replace(getData(), fIndex);
|
||||
|
@ -179,12 +205,6 @@ public class AsyncDataViewer
|
|||
}
|
||||
}
|
||||
|
||||
private void queryValue(final int index) {
|
||||
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
|
||||
fItemDataRequestMonitors.add(rm);
|
||||
fDataGenerator.getValue(index, rm);
|
||||
}
|
||||
|
||||
private void cancelStaleRequests(int topIdx, int botIdx) {
|
||||
// Decrement the count of outstanding cancel calls.
|
||||
fCancelCallsPending--;
|
||||
|
@ -194,7 +214,10 @@ public class AsyncDataViewer
|
|||
|
||||
// Go through the outstanding requests and cancel any that
|
||||
// are not visible anymore.
|
||||
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
|
||||
for (Iterator<ValueDataRequestMonitor> itr =
|
||||
fItemDataRequestMonitors.iterator();
|
||||
itr.hasNext();)
|
||||
{
|
||||
ValueDataRequestMonitor item = itr.next();
|
||||
if (item.fIndex < topIdx || item.fIndex > botIdx) {
|
||||
// Set the item to canceled status, so that the data provider
|
||||
|
@ -237,14 +260,16 @@ public class AsyncDataViewer
|
|||
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||
|
||||
// Create the table viewer.
|
||||
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||
TableViewer tableViewer =
|
||||
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||
tableViewer.getControl().setLayoutData(data);
|
||||
|
||||
// Create the data generator.
|
||||
final IDataGenerator generator = new DataGeneratorWithExecutor();
|
||||
|
||||
// Create the content provider which will populate the viewer.
|
||||
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
|
||||
AsyncDataViewer contentProvider =
|
||||
new AsyncDataViewer(tableViewer, generator);
|
||||
tableViewer.setContentProvider(contentProvider);
|
||||
tableViewer.setInput(new Object());
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Wind River 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
|
||||
*
|
||||
* Contributors:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
//#ifdef exercises
|
||||
package org.eclipse.cdt.examples.dsf.dataviewer;
|
||||
//#else
|
||||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
|
||||
/**
|
||||
* A data generator which performs a sum computation on data retrieved from a
|
||||
* number of other data generators. The data retrieval from other generators
|
||||
* is performed in parallel and the result is calculated once all data is
|
||||
* received.
|
||||
* <p>
|
||||
* This calculating generator does not listen to events from the data
|
||||
* providers so it relies on the client to re-retrieve data as needed.
|
||||
* </p>
|
||||
*/
|
||||
public class AsyncSumDataGenerator implements IDataGenerator {
|
||||
|
||||
/**
|
||||
* DSF executor used to serialize data access within this data generator.
|
||||
*/
|
||||
final private DsfExecutor fExecutor;
|
||||
|
||||
/**
|
||||
* Data generators to retrieve original data to perform calculations on.
|
||||
*/
|
||||
final private IDataGenerator[] fDataGenerators;
|
||||
|
||||
public AsyncSumDataGenerator(DsfExecutor executor,
|
||||
IDataGenerator[] generators)
|
||||
{
|
||||
fExecutor = executor;
|
||||
fDataGenerators = generators;
|
||||
}
|
||||
|
||||
public void getCount(final DataRequestMonitor<Integer> rm) {
|
||||
// Artificially delay the retrieval of the sum data to simulate
|
||||
// real processing time.
|
||||
fExecutor.schedule( new Runnable() {
|
||||
public void run() {
|
||||
doGetCount(rm);
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual count retrieval and calculation.
|
||||
* @param rm Request monitor to complete with data.
|
||||
*/
|
||||
private void doGetCount(final DataRequestMonitor<Integer> rm) {
|
||||
// Array to store counts retrieved asynchronously
|
||||
final int[] counts = new int[fDataGenerators.length];
|
||||
|
||||
// Counting request monitor is called once all data is retrieved.
|
||||
final CountingRequestMonitor crm =
|
||||
new CountingRequestMonitor(fExecutor, rm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
// Pick the highest count value.
|
||||
Arrays.sort(counts, 0, counts.length - 1);
|
||||
int maxCount = counts[counts.length - 1];
|
||||
rm.setData(maxCount);
|
||||
rm.done();
|
||||
};
|
||||
};
|
||||
|
||||
// Each call to data generator fills in one value in array.
|
||||
for (int i = 0; i < fDataGenerators.length; i++) {
|
||||
final int finalI = i;
|
||||
fDataGenerators[i].getCount(
|
||||
new DataRequestMonitor<Integer>(
|
||||
ImmediateExecutor.getInstance(), crm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
counts[finalI] = getData();
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
crm.setDoneCount(fDataGenerators.length);
|
||||
}
|
||||
|
||||
public void getValue(final int index, final DataRequestMonitor<Integer> rm)
|
||||
{
|
||||
// Artificially delay the retrieval of the sum data to simulate
|
||||
// real processing time.
|
||||
fExecutor.schedule( new Runnable() {
|
||||
public void run() {
|
||||
doGetValue(index, rm);
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual value retrieval and calculation.
|
||||
* @param rm Request monitor to complete with data.
|
||||
*/
|
||||
private void doGetValue(int index, final DataRequestMonitor<Integer> rm) {
|
||||
// Array to store counts retrieved asynchronously
|
||||
final int[] values = new int[fDataGenerators.length];
|
||||
|
||||
// Counting request monitor is called once all data is retrieved.
|
||||
final CountingRequestMonitor crm =
|
||||
new CountingRequestMonitor(fExecutor, rm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
// Sum up values in array.
|
||||
int sum = 0;
|
||||
for (int value : values) {
|
||||
sum += value;
|
||||
}
|
||||
rm.setData(sum);
|
||||
rm.done();
|
||||
};
|
||||
};
|
||||
|
||||
// Each call to data generator fills in one value in array.
|
||||
for (int i = 0; i < fDataGenerators.length; i++) {
|
||||
final int finalI = i;
|
||||
fDataGenerators[i].getValue(
|
||||
index,
|
||||
new DataRequestMonitor<Integer>(
|
||||
ImmediateExecutor.getInstance(), crm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
values[finalI] = getData();
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
crm.setDoneCount(fDataGenerators.length);
|
||||
}
|
||||
|
||||
public void shutdown(RequestMonitor rm) {
|
||||
rm.done();
|
||||
}
|
||||
|
||||
public void addListener(final Listener listener) {
|
||||
// no events generated
|
||||
}
|
||||
|
||||
public void removeListener(Listener listener) {
|
||||
// no events generated
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,410 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Wind River 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
|
||||
*
|
||||
* Contributors:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
//#ifdef exercises
|
||||
package org.eclipse.cdt.examples.dsf.dataviewer;
|
||||
//#else
|
||||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
|
||||
import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
|
||||
import org.eclipse.jface.viewers.ILazyContentProvider;
|
||||
import org.eclipse.jface.viewers.TableViewer;
|
||||
import org.eclipse.jface.viewers.Viewer;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
|
||||
/**
|
||||
* Data viewer based on a table, which reads data from multiple data
|
||||
* providers using asynchronous methods and performs a compultation
|
||||
* on the retrieved data.
|
||||
* <p>
|
||||
* This example builds on the {@link AsyncDataViewer} example and
|
||||
* demonstrates the pitfalls of retrieving data from multiple sources
|
||||
* asynchronously: The data is retrieved separate from a set of providers
|
||||
* as well as from a data provider that sums the values from the other
|
||||
* providers. The viewer then performs a check to ensure consistency of
|
||||
* retrieved data. If the retrieved data is inconsistent an "INCORRECT"
|
||||
* label is added in the viewer.
|
||||
* </p>
|
||||
* <p>
|
||||
* This viewer is updated periodically every 10 seconds, instead of being
|
||||
* updated with every change in every data provider, which would overwhelm
|
||||
* the viewer.
|
||||
* </p>
|
||||
*/
|
||||
@ConfinedToDsfExecutor("fDisplayExecutor")
|
||||
public class AsyncSumDataViewer implements ILazyContentProvider
|
||||
{
|
||||
/** View update frequency interval. */
|
||||
final private static int UPDATE_INTERVAL = 10000;
|
||||
|
||||
/** Executor to use instead of Display.asyncExec(). **/
|
||||
@ThreadSafe
|
||||
final private DsfExecutor fDisplayExecutor;
|
||||
|
||||
// The viewer and generator that this content provider using.
|
||||
final private TableViewer fViewer;
|
||||
final private IDataGenerator[] fDataGenerators;
|
||||
final private IDataGenerator fSumGenerator;
|
||||
|
||||
// Fields used in request cancellation logic.
|
||||
private List<ValueCountingRequestMonitor> fItemDataRequestMonitors =
|
||||
new LinkedList<ValueCountingRequestMonitor>();
|
||||
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
|
||||
private int fCancelCallsPending = 0;
|
||||
private Future<?> fRefreshFuture;
|
||||
|
||||
public AsyncSumDataViewer(TableViewer viewer,
|
||||
IDataGenerator[] generators, IDataGenerator sumGenerator)
|
||||
{
|
||||
fViewer = viewer;
|
||||
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
|
||||
fViewer.getTable().getDisplay());
|
||||
fDataGenerators = generators;
|
||||
fSumGenerator = sumGenerator;
|
||||
|
||||
// Schedule a task to refresh the viewer periodically.
|
||||
fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
queryItemCount();
|
||||
}
|
||||
},
|
||||
UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
// Cancel the periodic task of refreshing the view.
|
||||
fRefreshFuture.cancel(false);
|
||||
|
||||
// Cancel any outstanding data requests.
|
||||
for (ValueCountingRequestMonitor rm : fItemDataRequestMonitors) {
|
||||
rm.cancel();
|
||||
}
|
||||
fItemDataRequestMonitors.clear();
|
||||
}
|
||||
|
||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||
// Set the initial count to the viewer after the input is set.
|
||||
queryItemCount();
|
||||
}
|
||||
|
||||
public void updateElement(final int index) {
|
||||
// Calculate the visible index range.
|
||||
final int topIdx = fViewer.getTable().getTopIndex();
|
||||
final int botIdx = topIdx + getVisibleItemCount(topIdx);
|
||||
|
||||
// Request the item for the given index.
|
||||
queryValue(index);
|
||||
|
||||
// Invoke a cancel task with a delay. The delay allows multiple cancel
|
||||
// calls to be combined together improving performance of the viewer.
|
||||
fCancelCallsPending++;
|
||||
fDisplayExecutor.execute(
|
||||
new Runnable() { public void run() {
|
||||
cancelStaleRequests(topIdx, botIdx);
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of visible items based on the top item index and
|
||||
* table bounds.
|
||||
* @param top Index of top item.
|
||||
* @return calculated number of items in viewer
|
||||
*/
|
||||
private int getVisibleItemCount(int top) {
|
||||
Table table = fViewer.getTable();
|
||||
int itemCount = table.getItemCount();
|
||||
return Math.min(
|
||||
(table.getBounds().height / table.getItemHeight()) + 2,
|
||||
itemCount - top);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the up to date count.
|
||||
*/
|
||||
private void queryItemCount() {
|
||||
// Note:The count is retrieved from the sum generator only, the sum
|
||||
// generator is responsible for calculating the count based on
|
||||
// individual data providers' counts.
|
||||
fIndexesToCancel.clear();
|
||||
fSumGenerator.getCount(
|
||||
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
setCountToViewer(getData());
|
||||
}
|
||||
@Override
|
||||
protected void handleRejectedExecutionException() {
|
||||
// Shutting down, ignore.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the givne count to the viewer. This will cause the viewer will
|
||||
* refresh all items' data as well.
|
||||
* @param count New count to set to viewer.
|
||||
*/
|
||||
private void setCountToViewer(int count) {
|
||||
if (!fViewer.getTable().isDisposed()) {
|
||||
fViewer.setItemCount(count);
|
||||
fViewer.getTable().clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves value of an element at given index. When complete the value
|
||||
* is written to the viewer.
|
||||
* @param index Index of value to retrieve.
|
||||
*/
|
||||
private void queryValue(final int index) {
|
||||
// Values retrieved asynchronously from providers are stored in local
|
||||
// arrays.
|
||||
final int[] values = new int[fDataGenerators.length];
|
||||
final int[] sum = new int[1];
|
||||
|
||||
// Counting request monitor is invoked when the required number of
|
||||
// value requests is completed.
|
||||
final ValueCountingRequestMonitor crm =
|
||||
new ValueCountingRequestMonitor(index)
|
||||
{
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
fItemDataRequestMonitors.remove(this);
|
||||
|
||||
// Check if the request completed successfully, otherwise
|
||||
// ignore it.
|
||||
if (isSuccess()) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
int calcSum = 0;
|
||||
for (int value : values) {
|
||||
if (result.length() != 0) result.append(" + ");
|
||||
result.append(value);
|
||||
calcSum += value;
|
||||
}
|
||||
result.append(" = ");
|
||||
result.append(sum[0]);
|
||||
if (calcSum != sum[0]) {
|
||||
result.append(" !INCORRECT! ");
|
||||
}
|
||||
setValueToViewer(fIndex, result.toString());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Request data from each data generator.
|
||||
for (int i = 0; i < fDataGenerators.length; i++) {
|
||||
final int finalI = i;
|
||||
fDataGenerators[i].getValue(
|
||||
index,
|
||||
// Use the display executor to construct the request monitor,
|
||||
// this will cause the handleCompleted() method to be
|
||||
// automatically called on the display thread.
|
||||
new DataRequestMonitor<Integer>(
|
||||
ImmediateExecutor.getInstance(), crm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
values[finalI] = getData();
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Separately request data from the sum data generator.
|
||||
fSumGenerator.getValue(
|
||||
index,
|
||||
new DataRequestMonitor<Integer>(
|
||||
ImmediateExecutor.getInstance(), crm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
sum[0] = getData();
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
|
||||
crm.setDoneCount(fDataGenerators.length + 1);
|
||||
fItemDataRequestMonitors.add(crm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the view value to the viewer.
|
||||
* <p>Note: This method must be called in the display thread. </p>
|
||||
* @param index Index of value to set.
|
||||
* @param value New value.
|
||||
*/
|
||||
private void setValueToViewer(int index, String value) {
|
||||
if (!fViewer.getTable().isDisposed()) {
|
||||
fViewer.replace(value, index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated class for data item requests. This class holds the index
|
||||
* argument so it can be examined when canceling stale requests.
|
||||
*/
|
||||
private class ValueCountingRequestMonitor extends CountingRequestMonitor {
|
||||
/** Index is used when canceling stale requests. */
|
||||
int fIndex;
|
||||
|
||||
ValueCountingRequestMonitor(int index) {
|
||||
super(fDisplayExecutor, null);
|
||||
fIndex = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRejectedExecutionException() {
|
||||
// Shutting down, ignore.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any outstanding value requests for items which are no longer
|
||||
* visible in the viewer.
|
||||
*
|
||||
* @param topIdx Index of top visible item in viewer.
|
||||
* @param botIdx Index of bottom visible item in viewer.
|
||||
*/
|
||||
private void cancelStaleRequests(int topIdx, int botIdx) {
|
||||
// Decrement the count of outstanding cancel calls.
|
||||
fCancelCallsPending--;
|
||||
|
||||
// Must check again, in case disposed while re-dispatching.
|
||||
if (fDataGenerators == null || fViewer.getTable().isDisposed()) return;
|
||||
|
||||
// Go through the outstanding requests and cancel any that
|
||||
// are not visible anymore.
|
||||
for (Iterator<ValueCountingRequestMonitor> itr =
|
||||
fItemDataRequestMonitors.iterator(); itr.hasNext();)
|
||||
{
|
||||
ValueCountingRequestMonitor item = itr.next();
|
||||
if (item.fIndex < topIdx || item.fIndex > botIdx) {
|
||||
// Set the item to canceled status, so that the data provider
|
||||
// will ignore it.
|
||||
item.cancel();
|
||||
|
||||
// Add the item index to list of indexes that were canceled,
|
||||
// which will be sent to the table widget.
|
||||
fIndexesToCancel.add(item.fIndex);
|
||||
|
||||
// Remove the item from the outstanding cancel requests.
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
|
||||
Set<Integer> canceledIdxs = fIndexesToCancel;
|
||||
fIndexesToCancel = new HashSet<Integer>();
|
||||
|
||||
// Clear the indexes of the canceled request, so that the
|
||||
// viewer knows to request them again when needed.
|
||||
// Note: clearing using TableViewer.clear(int) seems very
|
||||
// inefficient, it's better to use Table.clear(int[]).
|
||||
int[] canceledIdxsArray = new int[canceledIdxs.size()];
|
||||
int i = 0;
|
||||
for (Integer index : canceledIdxs) {
|
||||
canceledIdxsArray[i++] = index;
|
||||
}
|
||||
fViewer.getTable().clear(canceledIdxsArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the example.
|
||||
* @param args Program arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Create the shell to hold the viewer.
|
||||
Display display = new Display();
|
||||
Shell shell = new Shell(display, SWT.SHELL_TRIM);
|
||||
shell.setLayout(new GridLayout());
|
||||
GridData data = new GridData(GridData.FILL_BOTH);
|
||||
shell.setLayoutData(data);
|
||||
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
|
||||
|
||||
// Create the table viewer.
|
||||
TableViewer tableViewer =
|
||||
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
|
||||
tableViewer.getControl().setLayoutData(data);
|
||||
|
||||
// Single executor (and single thread) is used by all data generators,
|
||||
// including the sum generator.
|
||||
DsfExecutor executor = new DefaultDsfExecutor("Example executor");
|
||||
|
||||
// Create the data generator.
|
||||
final IDataGenerator[] generators = new IDataGenerator[5];
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
generators[i] = new DataGeneratorWithExecutor(executor);
|
||||
}
|
||||
final IDataGenerator sumGenerator =
|
||||
new AsyncSumDataGenerator(executor, generators);
|
||||
|
||||
// Create the content provider which will populate the viewer.
|
||||
AsyncSumDataViewer contentProvider =
|
||||
new AsyncSumDataViewer(tableViewer, generators, sumGenerator);
|
||||
tableViewer.setContentProvider(contentProvider);
|
||||
tableViewer.setInput(new Object());
|
||||
|
||||
// Open the shell and service the display dispatch loop until user
|
||||
// closes the shell.
|
||||
shell.open();
|
||||
while (!shell.isDisposed()) {
|
||||
if (!display.readAndDispatch())
|
||||
display.sleep();
|
||||
}
|
||||
|
||||
// The IDataGenerator.shutdown() method is asynchronous, this requires
|
||||
// using a query again in order to wait for its completion.
|
||||
Query<Object> shutdownQuery = new Query<Object>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<Object> rm) {
|
||||
CountingRequestMonitor crm = new CountingRequestMonitor(
|
||||
ImmediateExecutor.getInstance(), rm);
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
generators[i].shutdown(crm);
|
||||
}
|
||||
sumGenerator.shutdown(crm);
|
||||
crm.setDoneCount(generators.length);
|
||||
}
|
||||
};
|
||||
|
||||
executor.execute(shutdownQuery);
|
||||
try {
|
||||
shutdownQuery.get();
|
||||
} catch (Exception e) {}
|
||||
|
||||
// Shut down the display.
|
||||
font.dispose();
|
||||
display.dispose();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Wind River 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
|
||||
*
|
||||
* Contributors:
|
||||
* Wind River Systems - initial API and implementation
|
||||
*******************************************************************************/
|
||||
//#ifdef exercises
|
||||
package org.eclipse.cdt.examples.dsf.dataviewer;
|
||||
//#else
|
||||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ICache;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestCache;
|
||||
import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
/**
|
||||
* A wrapper class for the {@link IDataGenerator} interface, which returns
|
||||
* ACPM cache objects to use for data retrieval instead of calling
|
||||
* {@link IDataGenerator} asynchronous methods directly.
|
||||
*/
|
||||
public class DataGeneratorCacheManager implements IDataGenerator.Listener {
|
||||
|
||||
/** Cache class for retrieving the data generator's count. */
|
||||
private class CountCache extends RequestCache<Integer> {
|
||||
|
||||
public CountCache() {
|
||||
super(fExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void retrieve(DataRequestMonitor<Integer> rm) {
|
||||
fDataGenerator.getCount(rm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cache when the count is changed.
|
||||
*/
|
||||
public void countChanged() {
|
||||
// Make sure that if clients are currently waiting for a count,
|
||||
// they are notified of the update (their request monitors will be
|
||||
// completed with an error). They shoudl then re-request data
|
||||
// from provider again.
|
||||
setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Count changed"));
|
||||
}
|
||||
}
|
||||
|
||||
/** Cache class for retrieving the data generator's values. */
|
||||
private class ValueCache extends RequestCache<Integer> {
|
||||
private int fIndex;
|
||||
|
||||
public ValueCache(int index) {
|
||||
super(fExecutor);
|
||||
fIndex = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor<Integer> rm) {
|
||||
fDataGenerator.getValue(fIndex, rm);
|
||||
};
|
||||
|
||||
/**
|
||||
* @see CountCache#countChanged()
|
||||
*/
|
||||
public void valueChanged() {
|
||||
setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Value changed"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executor used to synchronize data access in this cache manager.
|
||||
* It has to be the same executor that is used by the data generators in
|
||||
* order to guarantee data consistency.
|
||||
*/
|
||||
private ImmediateInDsfExecutor fExecutor;
|
||||
|
||||
/**
|
||||
* Data generator that this cache manager is a wrapper for.
|
||||
*/
|
||||
private IDataGenerator fDataGenerator;
|
||||
|
||||
/** Cache for data generator's count */
|
||||
private CountCache fCountCache;
|
||||
|
||||
/**
|
||||
* Map of caches for retrieving values. Each value index has a separate
|
||||
* cache value object.
|
||||
*/
|
||||
private Map<Integer, ValueCache> fValueCaches = new HashMap<Integer, ValueCache>();
|
||||
|
||||
public DataGeneratorCacheManager(ImmediateInDsfExecutor executor, IDataGenerator dataGenerator) {
|
||||
fExecutor = executor;
|
||||
fDataGenerator = dataGenerator;
|
||||
fDataGenerator.addListener(this);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
fDataGenerator.removeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data generator that this cache manager wraps.
|
||||
*/
|
||||
public IDataGenerator getDataGenerator() {
|
||||
return fDataGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache for data generator count.
|
||||
*/
|
||||
public ICache<Integer> getCount() {
|
||||
if (fCountCache == null) {
|
||||
fCountCache = new CountCache();
|
||||
}
|
||||
return fCountCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache for a value at given index.
|
||||
*
|
||||
* @param index Index of value to return.
|
||||
* @return Cache object for given value.
|
||||
*/
|
||||
public ICache<Integer> getValue(int index) {
|
||||
ValueCache value = fValueCaches.get(index);
|
||||
if (value == null) {
|
||||
value = new ValueCache(index);
|
||||
fValueCaches.put(index, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void countChanged() {
|
||||
// Reset the count cache and all the value caches.
|
||||
if (fCountCache != null) {
|
||||
fCountCache.countChanged();
|
||||
}
|
||||
for (ValueCache value : fValueCaches.values()) {
|
||||
value.valueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void valuesChanged(Set<Integer> indexes) {
|
||||
// Reset selected value caches.
|
||||
for (Integer index : indexes) {
|
||||
ValueCache value = fValueCaches.get(index);
|
||||
if (value != null) {
|
||||
value.valueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2009 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2011 Wind River 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
|
||||
|
@ -14,14 +14,14 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
|
|||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
//#ifdef answers
|
||||
//#import java.util.Iterator;
|
||||
//#endif
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -70,6 +70,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
|
||||
Request(RequestMonitor rm) {
|
||||
fRequestMonitor = rm;
|
||||
|
||||
rm.addCancelListener(new RequestMonitor.ICanceledListener() {
|
||||
public void requestCanceled(RequestMonitor rm) {
|
||||
fExecutor.execute(new DsfRunnable() {
|
||||
public void run() {
|
||||
fQueue.remove(Request.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +103,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//#endif
|
||||
class ItemRequest extends Request {
|
||||
final int fIndex;
|
||||
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||
ItemRequest(int index, DataRequestMonitor<Integer> rm) {
|
||||
super(rm);
|
||||
fIndex = index;
|
||||
}
|
||||
|
@ -156,24 +166,20 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//#else
|
||||
//# @ConfinedToDsfExecutor("fExecutor")
|
||||
//#endif
|
||||
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
|
||||
private Map<Integer, Integer> fChangedValues =
|
||||
new HashMap<Integer, Integer>();
|
||||
|
||||
// Flag used to ensure that requests are processed sequentially.
|
||||
//#ifdef exercises
|
||||
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||
// indicating allowed thread access to this class/method/member
|
||||
//#else
|
||||
//# @ConfinedToDsfExecutor("fExecutor")
|
||||
//#endif
|
||||
private boolean fServiceQueueInProgress = false;
|
||||
|
||||
//#ifdef exercises
|
||||
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||
// indicating allowed thread access to this class/method/member
|
||||
//#endif
|
||||
public DataGeneratorWithExecutor() {
|
||||
// Create the executor
|
||||
fExecutor = new DefaultDsfExecutor("Supplier Executor");
|
||||
this(new DefaultDsfExecutor("Supplier Executor"));
|
||||
}
|
||||
//#ifdef exercises
|
||||
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||
// indicating allowed thread access to this class/method/member
|
||||
//#endif
|
||||
public DataGeneratorWithExecutor(DsfExecutor executor) {
|
||||
// Create the executor
|
||||
fExecutor = executor;
|
||||
|
||||
// Schedule a runnable to make the random changes.
|
||||
fExecutor.scheduleAtFixedRate(
|
||||
|
@ -182,8 +188,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
randomChanges();
|
||||
}
|
||||
},
|
||||
RANDOM_CHANGE_INTERVAL,
|
||||
RANDOM_CHANGE_INTERVAL,
|
||||
new Random().nextInt() % RANDOM_CHANGE_INTERVAL,
|
||||
RANDOM_CHANGE_INTERVAL, //Add a 10% variance to the interval.
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
@ -197,8 +203,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
public void run() {
|
||||
// Empty the queue of requests and fail them.
|
||||
for (Request request : fQueue) {
|
||||
request.fRequestMonitor.setStatus(
|
||||
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
request.fRequestMonitor.setStatus(new Status(
|
||||
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
request.fRequestMonitor.done();
|
||||
}
|
||||
fQueue.clear();
|
||||
|
@ -209,7 +216,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +235,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(
|
||||
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +246,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
|
||||
// indicating allowed thread access to this class/method/member
|
||||
//#endif
|
||||
public void getValue(final int index, final DataRequestMonitor<String> rm) {
|
||||
public void getValue(final int index, final DataRequestMonitor<Integer> rm) {
|
||||
try {
|
||||
fExecutor.execute( new DsfRunnable() {
|
||||
public void run() {
|
||||
|
@ -245,7 +255,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +297,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//# @ConfinedToDsfExecutor("fExecutor")
|
||||
//#endif
|
||||
private void serviceQueue() {
|
||||
fExecutor.schedule(
|
||||
new DsfRunnable() {
|
||||
public void run() {
|
||||
doServiceQueue();
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void doServiceQueue() {
|
||||
//#ifdef exercises
|
||||
// TODO Exercise 3 - Add logic to discard cancelled requests from queue.
|
||||
// Hint: Since serviceQueue() is called using the executor, and the
|
||||
|
@ -305,33 +325,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//# }
|
||||
//#endif
|
||||
|
||||
// If a queue servicing is already scheduled, do nothing.
|
||||
if (fServiceQueueInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fQueue.size() != 0) {
|
||||
while (fQueue.size() != 0) {
|
||||
// If there are requests to service, remove one from the queue and
|
||||
// schedule a runnable to process the request after a processing
|
||||
// delay.
|
||||
fServiceQueueInProgress = true;
|
||||
final Request request = fQueue.remove(0);
|
||||
fExecutor.schedule(
|
||||
new DsfRunnable() {
|
||||
public void run() {
|
||||
Request request = fQueue.remove(0);
|
||||
if (request instanceof CountRequest) {
|
||||
processCountRequest((CountRequest)request);
|
||||
} else if (request instanceof ItemRequest) {
|
||||
processItemRequest((ItemRequest)request);
|
||||
}
|
||||
|
||||
// Reset the processing flag and process next
|
||||
// request.
|
||||
fServiceQueueInProgress = false;
|
||||
serviceQueue();
|
||||
}
|
||||
},
|
||||
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +346,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//#endif
|
||||
private void processCountRequest(CountRequest request) {
|
||||
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
DataRequestMonitor<Integer> rm =
|
||||
(DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
|
||||
rm.setData(fCount);
|
||||
rm.done();
|
||||
|
@ -357,12 +361,13 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
//#endif
|
||||
private void processItemRequest(ItemRequest request) {
|
||||
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||
DataRequestMonitor<Integer> rm =
|
||||
(DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
|
||||
if (fChangedIndexes.contains(request.fIndex)) {
|
||||
rm.setData("Changed: " + request.fIndex);
|
||||
if (fChangedValues.containsKey(request.fIndex)) {
|
||||
rm.setData(fChangedValues.get(request.fIndex));
|
||||
} else {
|
||||
rm.setData(Integer.toString(request.fIndex));
|
||||
rm.setData(request.fIndex);
|
||||
}
|
||||
rm.done();
|
||||
}
|
||||
|
@ -398,10 +403,11 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
private void randomCountReset() {
|
||||
// Calculate the new count.
|
||||
Random random = new java.util.Random();
|
||||
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||
fCount = MIN_COUNT +
|
||||
Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||
|
||||
// Reset the changed values.
|
||||
fChangedIndexes.clear();
|
||||
fChangedValues.clear();
|
||||
|
||||
// Notify listeners
|
||||
for (Listener listener : fListeners) {
|
||||
|
@ -421,17 +427,19 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
|
|||
private void randomDataChange() {
|
||||
// Calculate the indexes to change.
|
||||
Random random = new java.util.Random();
|
||||
Set<Integer> set = new HashSet<Integer>();
|
||||
Map<Integer, Integer> changed = new HashMap<Integer, Integer>();
|
||||
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||
int randomIndex = Math.abs(random.nextInt()) % fCount;
|
||||
int randomValue = Math.abs(random.nextInt()) % fCount;
|
||||
changed.put(randomIndex, randomValue);
|
||||
}
|
||||
|
||||
// Add the indexes to an overall set of changed indexes.
|
||||
fChangedIndexes.addAll(set);
|
||||
fChangedValues.putAll(changed);
|
||||
|
||||
// Notify listeners
|
||||
for (Listener listener : fListeners) {
|
||||
listener.valuesChanged(set);
|
||||
for (Object listener : fListeners) {
|
||||
((Listener)listener).valuesChanged(changed.keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2009 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2011 Wind River 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
|
||||
|
@ -15,9 +15,9 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
|
|||
//#endif
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -41,7 +41,9 @@ import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
|
|||
* synchronization.
|
||||
* </p>
|
||||
*/
|
||||
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
||||
public class DataGeneratorWithThread extends Thread
|
||||
implements IDataGenerator
|
||||
{
|
||||
|
||||
// Request objects are used to serialize the interface calls into objects
|
||||
// which can then be pushed into a queue.
|
||||
|
@ -61,7 +63,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
|
||||
class ItemRequest extends Request {
|
||||
final int fIndex;
|
||||
ItemRequest(int index, DataRequestMonitor<String> rm) {
|
||||
ItemRequest(int index, DataRequestMonitor<Integer> rm) {
|
||||
super(rm);
|
||||
fIndex = index;
|
||||
}
|
||||
|
@ -76,7 +78,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
// Main request queue of the data generator. The getValue(), getCount(),
|
||||
// and shutdown() methods write into the queue, while the run() method
|
||||
// reads from it.
|
||||
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
|
||||
private final BlockingQueue<Request> fQueue =
|
||||
new LinkedBlockingQueue<Request>();
|
||||
|
||||
// ListenerList class provides thread safety.
|
||||
private ListenerList fListeners = new ListenerList();
|
||||
|
@ -88,7 +91,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
private int fCountResetTrigger = 0;
|
||||
|
||||
// Elements which were modified since the last reset.
|
||||
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
|
||||
private Map<Integer, Integer> fChangedValues =
|
||||
Collections.synchronizedMap(new HashMap<Integer, Integer>());
|
||||
|
||||
// Used to determine when to make changes in data.
|
||||
private long fLastChangeTime = System.currentTimeMillis();
|
||||
|
@ -108,7 +112,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
fQueue.add(new ShutdownRequest(rm));
|
||||
} else {
|
||||
//
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
@ -117,16 +122,18 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
if (!fShutdown.get()) {
|
||||
fQueue.add(new CountRequest(rm));
|
||||
} else {
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
||||
public void getValue(int index, DataRequestMonitor<String> rm) {
|
||||
public void getValue(int index, DataRequestMonitor<Integer> rm) {
|
||||
if (!fShutdown.get()) {
|
||||
fQueue.add(new ItemRequest(index, rm));
|
||||
} else {
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
|
||||
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
|
||||
"Supplier shut down"));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +157,6 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
// If a request was dequeued, process it.
|
||||
if (request != null) {
|
||||
// Simulate a processing delay.
|
||||
Thread.sleep(PROCESSING_DELAY);
|
||||
|
||||
if (request instanceof CountRequest) {
|
||||
processCountRequest((CountRequest)request);
|
||||
|
@ -162,6 +168,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
request.fRequestMonitor.done();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Thread.sleep(PROCESSING_DELAY);
|
||||
}
|
||||
|
||||
// Simulate data changes.
|
||||
|
@ -173,7 +181,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
|
||||
private void processCountRequest(CountRequest request) {
|
||||
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
DataRequestMonitor<Integer> rm =
|
||||
(DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
|
||||
rm.setData(fCount);
|
||||
rm.done();
|
||||
|
@ -181,12 +190,13 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
|
||||
private void processItemRequest(ItemRequest request) {
|
||||
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
|
||||
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
|
||||
DataRequestMonitor<Integer> rm =
|
||||
(DataRequestMonitor<Integer>)request.fRequestMonitor;
|
||||
|
||||
if (fChangedIndexes.contains(request.fIndex)) {
|
||||
rm.setData("Changed: " + request.fIndex);
|
||||
if (fChangedValues.containsKey(request.fIndex)) {
|
||||
rm.setData(fChangedValues.get(request.fIndex));
|
||||
} else {
|
||||
rm.setData(Integer.toString(request.fIndex));
|
||||
rm.setData(request.fIndex);
|
||||
}
|
||||
rm.done();
|
||||
}
|
||||
|
@ -194,7 +204,9 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
|
||||
private void randomChanges() {
|
||||
// Check if enough time is elapsed.
|
||||
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
|
||||
if (System.currentTimeMillis() >
|
||||
fLastChangeTime + RANDOM_CHANGE_INTERVAL)
|
||||
{
|
||||
fLastChangeTime = System.currentTimeMillis();
|
||||
|
||||
// Once every number of changes, reset the count, the rest of the
|
||||
|
@ -213,7 +225,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
|
||||
|
||||
// Reset the changed values.
|
||||
fChangedIndexes.clear();
|
||||
fChangedValues.clear();
|
||||
|
||||
// Notify listeners
|
||||
for (Object listener : fListeners.getListeners()) {
|
||||
|
@ -224,17 +236,19 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
|
|||
private void randomDataChange() {
|
||||
// Calculate the indexes to change.
|
||||
Random random = new java.util.Random();
|
||||
Set<Integer> set = new HashSet<Integer>();
|
||||
Map<Integer, Integer> changed = new HashMap<Integer, Integer>();
|
||||
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
|
||||
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
|
||||
int randomIndex = Math.abs(random.nextInt()) % fCount;
|
||||
int randomValue = Math.abs(random.nextInt()) % fCount;
|
||||
changed.put(randomIndex, randomValue);
|
||||
}
|
||||
|
||||
// Add the indexes to an overall set of changed indexes.
|
||||
fChangedIndexes.addAll(set);
|
||||
fChangedValues.putAll(changed);
|
||||
|
||||
// Notify listeners
|
||||
for (Object listener : fListeners.getListeners()) {
|
||||
((Listener)listener).valuesChanged(set);
|
||||
((Listener)listener).valuesChanged(changed.keySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2009 Wind River Systems and others.
|
||||
* Copyright (c) 2006, 2011 Wind River 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
|
||||
|
@ -41,11 +41,11 @@ public interface IDataGenerator {
|
|||
// Changing the count range can stress the scalability of the system, while
|
||||
// changing of the process delay and random change interval can stress
|
||||
// its performance.
|
||||
final static int MIN_COUNT = 100;
|
||||
final static int MAX_COUNT = 200;
|
||||
final static int PROCESSING_DELAY = 10;
|
||||
final static int RANDOM_CHANGE_INTERVAL = 10000;
|
||||
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
|
||||
final static int MIN_COUNT = 50;
|
||||
final static int MAX_COUNT = 100;
|
||||
final static int PROCESSING_DELAY = 500;
|
||||
final static int RANDOM_CHANGE_INTERVAL = 4000;
|
||||
final static int RANDOM_COUNT_CHANGE_INTERVALS = 5;
|
||||
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ public interface IDataGenerator {
|
|||
|
||||
// Data access methods.
|
||||
void getCount(DataRequestMonitor<Integer> rm);
|
||||
void getValue(int index, DataRequestMonitor<String> rm);
|
||||
void getValue(int index, DataRequestMonitor<Integer> rm);
|
||||
|
||||
// Method used to shutdown the data generator including any threads that
|
||||
// it may use.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008, 2009 Wind River Systems and others.
|
||||
* Copyright (c) 2008, 2011 Wind River 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
|
||||
|
@ -14,8 +14,11 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
|
|||
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
|
||||
//#endif
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
|
@ -35,8 +38,8 @@ import org.eclipse.swt.widgets.Shell;
|
|||
* This viewer implements the {@link IStructuredContentProvider} interface
|
||||
* which is used by the JFace TableViewer class to populate a Table. This
|
||||
* interface contains one principal methods for reading data {@link #getElements(Object)},
|
||||
* which synchronously returns an array of elements. In order to implement this
|
||||
* method using the asynchronous data generator, this provider uses the
|
||||
* which synchronously returns an array of elements. In order to implement
|
||||
* this method using the asynchronous data generator, this provider uses the
|
||||
* {@link Query} object.
|
||||
* </p>
|
||||
*/
|
||||
|
@ -84,27 +87,43 @@ public class SyncDataViewer
|
|||
return new Object[0];
|
||||
}
|
||||
|
||||
// Create the array that will be filled with elements.
|
||||
// For each index in the array execute a query to get the element at
|
||||
// that index.
|
||||
final Object[] elements = new Object[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final int index = i;
|
||||
Query<String> valueQuery = new Query<String>() {
|
||||
final int finalCount = count;
|
||||
Query<List<Integer>> valueQuery = new Query<List<Integer>>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<String> rm) {
|
||||
fDataGenerator.getValue(index, rm);
|
||||
protected void execute(final DataRequestMonitor<List<Integer>> rm) {
|
||||
final Integer[] retVal = new Integer[finalCount];
|
||||
final CountingRequestMonitor crm = new CountingRequestMonitor(
|
||||
ImmediateExecutor.getInstance(), rm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
rm.setData(Arrays.asList(retVal));
|
||||
rm.done();
|
||||
};
|
||||
};
|
||||
for (int i = 0; i < finalCount; i++) {
|
||||
final int finalI = i;
|
||||
fDataGenerator.getValue(
|
||||
i,
|
||||
new DataRequestMonitor<Integer>(
|
||||
ImmediateExecutor.getInstance(), crm)
|
||||
{
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
retVal[finalI] = getData();
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
crm.setDoneCount(finalCount);
|
||||
}
|
||||
};
|
||||
ImmediateExecutor.getInstance().execute(valueQuery);
|
||||
try {
|
||||
elements[i] = valueQuery.get();
|
||||
return valueQuery.get().toArray(new Integer[0]);
|
||||
} catch (Exception e) {
|
||||
elements[i] = "error";
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
return new Object[0];
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
@ -140,6 +159,10 @@ public class SyncDataViewer
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for the example.
|
||||
* @param args Program arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// Create the shell to hold the viewer.
|
||||
Display display = new Display();
|
||||
|
@ -162,7 +185,8 @@ public class SyncDataViewer
|
|||
//#endif
|
||||
|
||||
// Create the content provider which will populate the viewer.
|
||||
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
|
||||
SyncDataViewer contentProvider =
|
||||
new SyncDataViewer(tableViewer, generator);
|
||||
tableViewer.setContentProvider(contentProvider);
|
||||
tableViewer.setInput(new Object());
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue