OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Checks Java files for illegal imports.""" | |
6 | |
7 import codecs | |
8 import os | |
9 import re | |
10 import sys | |
11 | |
12 | |
13 class JavaChecker(object): | |
14 """Import checker for Java files. | |
15 | |
16 The CheckFile method uses real filesystem paths, but Java imports work in | |
17 terms of package names. To deal with this, we have an extra "prescan" pass | |
18 that reads all the .java files and builds a mapping of class name -> filepath. | |
19 In CheckFile, we convert each import statement into a real filepath, and check | |
20 that against the rules in the DEPS files. | |
21 | |
22 Note that in Java you can always use classes in the same directory without an | |
23 explicit import statement, so these imports can't be blocked with DEPS files. | |
24 But that shouldn't be a problem, because same-package imports are pretty much | |
25 always correct by definition. (If we find a case where this is *not* correct, | |
26 it probably means the package is too big and needs to be split up.) | |
27 | |
28 Properties: | |
29 _classmap: dict of fully-qualified Java class name -> filepath | |
30 """ | |
31 | |
32 EXTENSIONS = ['.java'] | |
33 | |
34 def __init__(self, base_directory, verbose): | |
35 self._base_directory = base_directory | |
36 self._verbose = verbose | |
37 self._classmap = {} | |
38 self._PrescanFiles() | |
39 | |
40 def _PrescanFiles(self): | |
41 for root, dirs, files in os.walk(self._base_directory): | |
42 # Skip unwanted subdirectories. TODO(husky): it would be better to do | |
43 # this via the skip_child_includes flag in DEPS files. Maybe hoist this | |
44 # prescan logic into checkdeps.py itself? | |
45 for d in dirs: | |
46 # Skip hidden directories. | |
47 if d.startswith('.'): | |
48 dirs.remove(d) | |
49 # Skip the "out" directory, as dealing with generated files is awkward. | |
50 # We don't want paths like "out/Release/lib.java" in our DEPS files. | |
51 # TODO(husky): We need some way of determining the "real" path to | |
52 # a generated file -- i.e., where it would be in source control if | |
53 # it weren't generated. | |
54 if d == 'out': | |
55 dirs.remove(d) | |
56 # Skip third-party directories. | |
57 if d == 'third_party': | |
58 dirs.remove(d) | |
59 for f in files: | |
60 if f.endswith('.java'): | |
61 self._PrescanFile(os.path.join(root, f)) | |
62 | |
63 def _PrescanFile(self, filepath): | |
64 filepath = os.path.relpath(filepath, self._base_directory) | |
65 if self._verbose: | |
66 print 'Prescanning: ' + filepath | |
67 with codecs.open(filepath, encoding='utf-8') as f: | |
68 short_class_name, _ = os.path.splitext(os.path.basename(filepath)) | |
69 for line in f: | |
70 for package in re.findall('^package ([\w\.]+);', line): | |
71 full_class_name = package + '.' + short_class_name | |
72 if full_class_name in self._classmap: | |
73 print 'WARNING: multiple definitions of %s:' % full_class_name | |
74 print ' ' + filepath | |
75 print ' ' + self._classmap[full_class_name] | |
76 print | |
77 else: | |
78 self._classmap[full_class_name] = filepath | |
79 return | |
80 print 'WARNING: no package definition found in %s' % filepath | |
81 | |
82 def CheckFile(self, rules, filepath): | |
83 if self._verbose: | |
84 print 'Checking: ' + filepath | |
85 | |
86 result = '' | |
87 with codecs.open(filepath, encoding='utf-8') as f: | |
88 for line in f: | |
89 for clazz in re.findall('^import\s+(?:static\s+)?([\w\.]+)\s*;', line): | |
90 if clazz not in self._classmap: | |
91 # Importing a class from outside the Chromium tree. That's fine -- | |
92 # it's probably a Java or Android system class. | |
93 continue | |
94 include_path = self._classmap[clazz] | |
95 (allowed, why_failed) = rules.DirAllowed(include_path) | |
96 if not allowed: | |
97 if self._verbose: | |
98 result += '\nFor ' + rules.__str__() | |
M-A Ruel
2012/07/18 14:19:37
Same.
Iain Merrick
2012/07/19 12:44:34
Done.
| |
99 result += 'Illegal include: "%s"\n Because of %s\n' % ( | |
100 include_path, why_failed) | |
101 if '{' in line: | |
102 # This is code, so we're finished reading imports for this file. | |
103 break | |
104 | |
105 return result | |
OLD | NEW |