From 5d6bfb7b1a498f7ef0ebc93bc93fc26fb89b9a34 Mon Sep 17 00:00:00 2001 From: MatthewMarinets Date: Thu, 28 Jun 2018 11:23:32 -0700 Subject: -Adjusted JavaCommon to deal with implementations of classes as constructor arguments. -Added a test to JavaCommonTests to test the new functionality. --- src/engine/SCons/Tool/JavaCommon.py | 97 ++++++++++++++++++++++++++++---- src/engine/SCons/Tool/JavaCommonTests.py | 43 ++++++++++++++ 2 files changed, 128 insertions(+), 12 deletions(-) diff --git a/src/engine/SCons/Tool/JavaCommon.py b/src/engine/SCons/Tool/JavaCommon.py index dfb9e33..7a065ca 100644 --- a/src/engine/SCons/Tool/JavaCommon.py +++ b/src/engine/SCons/Tool/JavaCommon.py @@ -37,6 +37,10 @@ java_parsing = 1 default_java_version = '1.4' +# a switch for which jdk versions to use the Scope state for smarter +# anonymous inner class parsing. +scopeStateVersions = ('1.8') + if java_parsing: # Parse Java files for class names. # @@ -64,7 +68,7 @@ if java_parsing: interfaces, and anonymous inner classes.""" def __init__(self, version=default_java_version): - if not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6', '1.7', + if not version in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8', '5', '6'): msg = "Java version %s not supported" % version raise NotImplementedError(msg) @@ -115,8 +119,8 @@ if java_parsing: ret = SkipState(1, self) self.skipState = ret return ret - - def __getAnonStack(self): + + def _getAnonStack(self): return self.anonStacksStack[-1] def openBracket(self): @@ -125,15 +129,16 @@ if java_parsing: def closeBracket(self): self.brackets = self.brackets - 1 if len(self.stackBrackets) and \ - self.brackets == self.stackBrackets[-1]: + self.brackets == self.stackBrackets[-1]: self.listOutputs.append('$'.join(self.listClasses)) self.localClasses.pop() self.listClasses.pop() self.anonStacksStack.pop() self.stackBrackets.pop() if len(self.stackAnonClassBrackets) and \ - self.brackets == self.stackAnonClassBrackets[-1]: - self.__getAnonStack().pop() + self.brackets == self.stackAnonClassBrackets[-1] and \ + self.version not in scopeStateVersions: + self._getAnonStack().pop() self.stackAnonClassBrackets.pop() def parseToken(self, token): @@ -175,17 +180,83 @@ if java_parsing: self.stackAnonClassBrackets.append(self.brackets) className = [] className.extend(self.listClasses) - self.__getAnonStack()[-1] = self.__getAnonStack()[-1] + 1 - for anon in self.__getAnonStack(): + self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1 + for anon in self._getAnonStack(): className.append(str(anon)) self.listOutputs.append('$'.join(className)) self.nextAnon = self.nextAnon + 1 - self.__getAnonStack().append(0) + self._getAnonStack().append(0) def setPackage(self, package): self.package = package + class ScopeState(object): + """ + A state that parses code within a scope normally, + within the confines of a scope. + """ + def __init__(self, old_state): + self.outer_state = old_state.outer_state + self.old_state = old_state + self.brackets = 0 + + def __getClassState(self): + try: + return self.classState + except AttributeError: + ret = ClassState(self) + self.classState = ret + return ret + + def __getAnonClassState(self): + try: + return self.anonState + except AttributeError: + ret = SkipState(1, AnonClassState(self)) + self.anonState = ret + return ret + + def __getSkipState(self): + try: + return self.skipState + except AttributeError: + ret = SkipState(1, self) + self.skipState = ret + return ret + + def openBracket(self): + self.brackets = self.brackets + 1 + + def closeBracket(self): + self.brackets = self.brackets - 1 + + def parseToken(self, token): + # if self.brackets == 0: + # return self.old_state.parseToken(token) + if token[:2] == '//': + return IgnoreState('\n', self) + elif token == '/*': + return IgnoreState('*/', self) + elif token == '{': + self.openBracket() + elif token == '}': + self.closeBracket() + if self.brackets == 0: + self.outer_state._getAnonStack().pop() + return self.old_state + elif token in ['"', "'"]: + return IgnoreState(token, self) + elif token == "new": + # anonymous inner class + return self.__getAnonClassState() + elif token == '.': + # Skip the attribute, it might be named "class", in which + # case we don't want to treat the following token as + # an inner class name... + return self.__getSkipState() + return self + class AnonClassState(object): """A state that looks for anonymous inner classes.""" def __init__(self, old_state): @@ -212,13 +283,15 @@ if java_parsing: if token == 'new': # look further for anonymous inner class return SkipState(1, AnonClassState(self)) - elif token in [ '"', "'" ]: + elif token in ['"', "'"]: return IgnoreState(token, self) elif token == ')': self.brace_level = self.brace_level - 1 return self if token == '{': self.outer_state.addAnonClass() + if self.outer_state.version in scopeStateVersions: + return ScopeState(old_state = self.old_state).parseToken(token) return self.old_state.parseToken(token) class SkipState(object): @@ -247,8 +320,8 @@ if java_parsing: # 'Foo$1Inner' # https://github.com/SCons/scons/issues/2087 if self.outer_state.localClasses and \ - self.outer_state.stackBrackets[-1] > \ - self.outer_state.stackBrackets[-2]+1: + self.outer_state.stackBrackets[-1] > \ + self.outer_state.stackBrackets[-2]+1: locals = self.outer_state.localClasses[-1] try: idx = locals[token] diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py index 902030d..7e6a482 100644 --- a/src/engine/SCons/Tool/JavaCommonTests.py +++ b/src/engine/SCons/Tool/JavaCommonTests.py @@ -566,6 +566,49 @@ public class Foo assert expect == classes, (expect, classes) + def test_in_function_class_declaration(self): + """ + Test that implementing a class in a function call doesn't confuse SCons. + """ + + input = """ +package com.Matthew; + +public class AnonDemo { + + public static void main(String[] args) { + new AnonDemo().execute(); + } + + public void execute() { + Foo bar = new Foo(new Foo() { + @Override + public int getX() { return this.x; } + }) { + @Override + public int getX() { return this.x; } + }; + } + + public abstract class Foo { + public int x; + public abstract int getX(); + + public Foo(Foo f) { + this.x = f.x; + } + + public Foo() {} + } +} +""" + expect = ['AnonDemo$1', + 'AnonDemo$2', + 'AnonDemo$Foo', + 'AnonDemo'] + pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.8') + assert expect == classes, (expect, classes) + if __name__ == "__main__": suite = unittest.TestSuite() -- cgit v0.12 From f1f2d14e1c9d155691675fc17e7d7a47f63b02f4 Mon Sep 17 00:00:00 2001 From: MatthewMarinets <31861583+MatthewMarinets@users.noreply.github.com> Date: Tue, 3 Jul 2018 09:35:31 -0700 Subject: Update CHANGES.txt --- src/CHANGES.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index b0baecb..5ecf245 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -6,7 +6,11 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE - + + From Matthew Marinets + - Fixed an issue that caused the Java emitter to incorrectly parse arguments to constructors that + implemented a class. + From Philipp Maierhöfer - Added a __hash__ method to the class Scons.Subst.Literal. Required when substituting Literal objects when SCons runs with Python 3. -- cgit v0.12 From 1e16a302b72ce5b5ecfc9b1c13588aec4a59daf3 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 17 Jul 2018 08:49:52 -0600 Subject: Fix typos from issue 3194 https://github.com/SCons/scons/issues/3149 Signed-off-by: Mats Wichmann --- doc/user/depends.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/user/depends.xml b/doc/user/depends.xml index 8e548d2..297eaa2 100644 --- a/doc/user/depends.xml +++ b/doc/user/depends.xml @@ -571,7 +571,7 @@ int main() { printf("Hello, world!\n"); } The content signature, or MD5 checksum, of the contents of the dependency - file the list time the ⌖ was built. + file the last time the ⌖ was built. @@ -583,7 +583,7 @@ int main() { printf("Hello, world!\n"); } The size in bytes of the dependency - file the list time the target was built. + file the last time the target was built. @@ -595,7 +595,7 @@ int main() { printf("Hello, world!\n"); } The modification time of the dependency - file the list time the ⌖ was built. + file the last time the ⌖ was built. -- cgit v0.12 From 58f4b2e91a62379b71246e4c882df82325c3f7fa Mon Sep 17 00:00:00 2001 From: Piotr Kasprzyk Date: Fri, 20 Jul 2018 16:04:30 +0200 Subject: Fix some misspellings, remove repeated: and Signed-off-by: Piotr Kasprzyk --- doc/user/environments.xml | 6 +++--- doc/user/parseflags.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/user/environments.xml b/doc/user/environments.xml index 2089dfe..65eed72 100644 --- a/doc/user/environments.xml +++ b/doc/user/environments.xml @@ -385,9 +385,9 @@ environment, of directory names, suffixes, etc. A &consenv; - is a distinct object creating within + is a distinct object created within a &SConscript; file and - and which contains values that + which contains values that affect how &SCons; decides what action to use to build a target, and even to define which targets @@ -1630,7 +1630,7 @@ env['ENV']['PATH'] = '/usr/local/bin:/bin:/usr/bin' But doing so makes your &SConscript; file less portable, (although in this case that may not be a huge concern - since the directories you list are likley system-specific, anyway). + since the directories you list are likely system-specific, anyway). diff --git a/doc/user/parseflags.xml b/doc/user/parseflags.xml index fa35d49..46d6866 100644 --- a/doc/user/parseflags.xml +++ b/doc/user/parseflags.xml @@ -57,7 +57,7 @@ &SCons; construction environments have a &ParseFlags; method that takes a set of typical command-line options - and distrbutes them into the appropriate construction variables. + and distributes them into the appropriate construction variables. Historically, it was created to support the &ParseConfig; method, so it focuses on options used by the GNU Compiler Collection (GCC) for the C and C++ toolchains. -- cgit v0.12 From bde85d7501235a67bee32c65f83a9e4da52e3968 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 24 Jul 2018 15:44:48 -0600 Subject: Fix py3 ResourceWarning in TestCmd class TestCmd method read() uses a shortcut to return data from a file, "return open(...).read()". Python 3 warns this is a resource leak because the file has no chance to be closed with the open being in the return statement. Split into two lines and use a context manager (with statement). Signed-off-by: Mats Wichmann --- src/CHANGES.txt | 1 + testing/framework/TestCmd.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 79d25db..e3a646c 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -102,6 +102,7 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE - xml validity fixes from SConstruct.py change - update wiki links to new github location - update bug links to new github location + - convert TestCmd.read to use with statement on open (quiets 17 py3 warnings) From Hao Wu - typo in customized decider example in user guide diff --git a/testing/framework/TestCmd.py b/testing/framework/TestCmd.py index 9cd6b39..9499ff4 100644 --- a/testing/framework/TestCmd.py +++ b/testing/framework/TestCmd.py @@ -1247,9 +1247,11 @@ class TestCmd(object): if mode[0] != 'r': raise ValueError("mode must begin with 'r'") if IS_PY3 and 'b' not in mode: - return open(file, mode, newline=newline).read() + with open(file, mode, newline=newline) as f: + return f.read() else: - return open(file, mode).read() + with open(file, mode) as f: + return f.read() def rmdir(self, dir): """Removes the specified dir name. -- cgit v0.12 From 8308dd2ad4286ac3c9e882913451e9e517a0a238 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 24 Jul 2018 17:43:59 -0600 Subject: Quiet UtilTest ResourceWarning Use context manager around file opens to quiet a Python 3 resource leak warning. Signed-off-by: Mats Wichmann --- src/CHANGES.txt | 1 + src/engine/SCons/UtilTests.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index e3a646c..26ed803 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -103,6 +103,7 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE - update wiki links to new github location - update bug links to new github location - convert TestCmd.read to use with statement on open (quiets 17 py3 warnings) + - quiet warning in UtilTests.py From Hao Wu - typo in customized decider example in user guide diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index 842d4d8..81ec09d 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -488,8 +488,10 @@ class UtilTestCase(unittest.TestCase): filename = tempfile.mktemp() str = '1234567890 ' + filename try: - open(filename, 'w').write(str) - assert open(get_native_path(filename)).read() == str + with open(filename, 'w') as f: + f.write(str) + with open(get_native_path(filename)) as f: + assert f.read() == str finally: try: os.unlink(filename) -- cgit v0.12 From a27c072faaa7dd5eb598d1df031c34e2f4492571 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 25 Jul 2018 06:28:59 -0600 Subject: Change octal constants in QT tests Resolving two test failures in Python 3 caused by: http://www.python.org/dev/peps/pep-3127/: octal literals must now be specified with a leading "0o" or "0O" instead of "0"; Signed-off-by: Mats Wichmann --- src/CHANGES.txt | 1 + test/QT/generated-ui.py | 2 +- test/QT/up-to-date.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 26ed803..c875f1f 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -104,6 +104,7 @@ RELEASE 3.1.0.alpha.yyyymmdd - NEW DATE WILL BE INSERTED HERE - update bug links to new github location - convert TestCmd.read to use with statement on open (quiets 17 py3 warnings) - quiet warning in UtilTests.py + - fix tests specifying octal constants for Py3 From Hao Wu - typo in customized decider example in user guide diff --git a/test/QT/generated-ui.py b/test/QT/generated-ui.py index e4632b1..4692a82 100644 --- a/test/QT/generated-ui.py +++ b/test/QT/generated-ui.py @@ -61,7 +61,7 @@ import SCons.Defaults def ExpHeaderScanner(node, env, path): return [] def generate(env): - HeaderAction=SCons.Action.Action([SCons.Defaults.Copy('$TARGET','$SOURCE'),SCons.Defaults.Chmod('$TARGET',0755)]) + HeaderAction=SCons.Action.Action([SCons.Defaults.Copy('$TARGET','$SOURCE'),SCons.Defaults.Chmod('$TARGET',0o755)]) HeaderBuilder= SCons.Builder.Builder(action=HeaderAction) env['BUILDERS']['ExportHeaders'] = HeaderBuilder def exists(env): diff --git a/test/QT/up-to-date.py b/test/QT/up-to-date.py index 21c758e..7a7e565 100644 --- a/test/QT/up-to-date.py +++ b/test/QT/up-to-date.py @@ -66,7 +66,7 @@ import SCons.Defaults def ExpHeaderScanner(node, env, path): return [] def generate(env): - HeaderAction=SCons.Action.Action([SCons.Defaults.Copy('$TARGET','$SOURCE'),SCons.Defaults.Chmod('$TARGET',0755)]) + HeaderAction=SCons.Action.Action([SCons.Defaults.Copy('$TARGET','$SOURCE'),SCons.Defaults.Chmod('$TARGET',0o755)]) HeaderBuilder= SCons.Builder.Builder(action=HeaderAction) env['BUILDERS']['ExportHeaders'] = HeaderBuilder def exists(env): -- cgit v0.12