Added support for Objective-C to CPD.

This commit is contained in:
Jan van Nunen
2015-01-08 16:04:15 +01:00
parent c1bc045c65
commit 8dd3755db1
17 changed files with 2037 additions and 0 deletions

File diff suppressed because it is too large Load Diff

96
pmd-objectivec/pom.xml Normal file
View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>pmd-objectivec</artifactId>
<name>PMD Objective-C</name>
<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>5.2.4-SNAPSHOT</version>
</parent>
<properties>
<config.basedir>${basedir}/../pmd-core</config.basedir>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<target>
<ant antfile="src/main/ant/alljavacc.xml">
<property name="target" value="${project.build.directory}/generated-sources/javacc" />
<property name="javacc.jar" value="${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar" />
</ant>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-javacc-generated-sources</id>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/javacc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<xdocDirectory>${project.build.directory}/generated-xdocs</xdocDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,45 @@
<project name="pmd" default="alljavacc" basedir="../../">
<property name="javacc-home.path" value="target/lib" />
<target name="alljavacc"
description="Generates all JavaCC aspects within PMD"
depends="checkUpToDate,init,objectivecjavacc,cleanup" />
<target name="checkUpToDate">
<uptodate property="javaccBuildNotRequired" targetfile="${target}/last-generated-timestamp">
<srcfiles dir="etc/grammar" includes="*.jj*"/>
</uptodate>
<echo message="up to date check: javaccBuildNotRequired=${javaccBuildNotRequired}"/>
</target>
<target name="init" unless="javaccBuildNotRequired">
<mkdir dir="${javacc-home.path}" />
<copy file="${javacc.jar}" tofile="${javacc-home.path}/javacc.jar" />
<mkdir dir="${target}"/>
<touch file="${target}/last-generated-timestamp"/>
</target>
<target name="cleanup">
<delete dir="${javacc-home.path}" />
</target>
<target name="objectivecjavacc" description="Generates the Objective-C grammar" unless="javaccBuildNotRequired">
<delete dir="${target}/net/sourceforge/pmd/lang/objectivec/ast" />
<mkdir dir="${target}/net/sourceforge/pmd/lang/objectivec/ast" />
<!-- Ensure generated using CharStream interface -->
<javacc static="false"
usercharstream="true"
target="etc/grammar/ObjC2.0.jj"
outputdirectory="${target}/net/sourceforge/pmd/lang/objectivec/ast"
javacchome="${javacc-home.path}" />
<replace file="${target}/net/sourceforge/pmd/lang/objectivec/ast/ObjectiveCParserTokenManager.java"
token="class ObjectiveCParserTokenManager"
value="class ObjectiveCParserTokenManager extends net.sourceforge.pmd.lang.ast.AbstractTokenManager" />
<delete file="${target}/net/sourceforge/pmd/lang/objectivec/ast/CharStream.java" />
<delete file="${target}/net/sourceforge/pmd/lang/objectivec/ast/ParseException.java" />
<delete file="${target}/net/sourceforge/pmd/lang/objectivec/ast/TokenMgrError.java" />
</target>
</project>

View File

@ -0,0 +1,18 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
/**
* Defines the Language module for Objective-C
*/
public class ObjectiveCLanguage extends AbstractLanguage {
/**
* Creates a new instance of {@link ObjectiveCLanguage} with the default extensions for Objective-C files.
*/
public ObjectiveCLanguage() {
super("Objective-C", "objectivec", new ObjectiveCTokenizer(), ".h", ".m");
}
}

View File

@ -0,0 +1,44 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.io.Reader;
import java.io.StringReader;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.TokenMgrError;
import net.sourceforge.pmd.lang.objectivec.ObjectiveCLanguageModule;
import net.sourceforge.pmd.lang.objectivec.ast.Token;
import org.apache.commons.io.IOUtils;
public class ObjectiveCTokenizer implements Tokenizer {
public void tokenize(SourceCode sourceCode, Tokens tokenEntries) {
StringBuilder buffer = sourceCode.getCodeBuffer();
Reader reader = null;
try {
LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(ObjectiveCLanguageModule.NAME)
.getDefaultVersion().getLanguageVersionHandler();
reader = new StringReader(buffer.toString());
TokenManager tokenManager = languageVersionHandler.getParser(
languageVersionHandler.getDefaultParserOptions()).getTokenManager(sourceCode.getFileName(), reader);
Token currentToken = (Token) tokenManager.getNextToken();
while (currentToken.image.length() > 0) {
tokenEntries.add(new TokenEntry(currentToken.image, sourceCode.getFileName(), currentToken.beginLine));
currentToken = (Token) tokenManager.getNextToken();
}
tokenEntries.add(TokenEntry.getEOF());
System.err.println("Added " + sourceCode.getFileName());
} catch (TokenMgrError err) {
err.printStackTrace();
System.err.println("Skipping " + sourceCode.getFileName() + " due to parse error");
tokenEntries.add(TokenEntry.getEOF());
} finally {
IOUtils.closeQuietly(reader);
}
}
}

View File

@ -0,0 +1,25 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.objectivec;
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
/**
* Implementation of LanguageVersionHandler for the Objective-C Language.
*/
public class ObjectiveCHandler extends AbstractLanguageVersionHandler {
@Override
public RuleViolationFactory getRuleViolationFactory() {
throw new UnsupportedOperationException("getRuleViolationFactory() is not supported for Objective-C");
}
@Override
public Parser getParser(ParserOptions parserOptions) {
return new ObjectiveCParser(parserOptions);
}
}

View File

@ -0,0 +1,25 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.objectivec;
import net.sourceforge.pmd.lang.BaseLanguageModule;
/**
* Implementation of the Objective-C Language Module.
*/
public class ObjectiveCLanguageModule extends BaseLanguageModule {
/** The name, that can be used to display the language in UI. */
public static final String NAME = "Objective-C";
/** The internal name. */
public static final String TERSE_NAME = "objectivec";
/**
* Creates a new instance of {@link ObjectiveCLanguageModule} with the default file extensions for Objective-C.
*/
public ObjectiveCLanguageModule() {
super(NAME, null, TERSE_NAME, null, "h", "m");
addVersion("", new ObjectiveCHandler(), true);
}
}

View File

@ -0,0 +1,49 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.objectivec;
import java.io.Reader;
import java.util.Map;
import net.sourceforge.pmd.lang.AbstractParser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.AbstractTokenManager;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
/**
* Adapter for the Objective-C Parser.
*/
public class ObjectiveCParser extends AbstractParser {
/**
* Creates a new Objective-C Parser.
* @param parserOptions the options
*/
public ObjectiveCParser(ParserOptions parserOptions) {
super(parserOptions);
}
@Override
public TokenManager createTokenManager(Reader source) {
return new ObjectiveCTokenManager(source);
}
@Override
public boolean canParse() {
return false;
}
@Override
public Node parse(String fileName, Reader source) throws ParseException {
AbstractTokenManager.setFileName(fileName);
throw new UnsupportedOperationException("parse(Reader) is not supported for Objective-C");
}
@Override
public Map<Integer, String> getSuppressMap() {
throw new UnsupportedOperationException("getSuppressMap() is not supported for Objective-C");
}
}

View File

@ -0,0 +1,34 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.objectivec;
import java.io.Reader;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.SimpleCharStream;
import net.sourceforge.pmd.lang.objectivec.ast.ObjectiveCParserTokenManager;
/**
* Objective-C Token Manager implementation.
*/
public class ObjectiveCTokenManager implements TokenManager {
private final ObjectiveCParserTokenManager tokenManager;
/**
* Creates a new Objective-C Token Manager from the given source code.
* @param source the source code
*/
public ObjectiveCTokenManager(Reader source) {
tokenManager = new ObjectiveCParserTokenManager(new SimpleCharStream(source));
}
public Object getNextToken() {
return tokenManager.getNextToken();
}
@Override
public void setFileName(String fileName) {
ObjectiveCParserTokenManager.setFileName(fileName);
}
}

View File

@ -0,0 +1 @@
net.sourceforge.pmd.cpd.ObjectiveCLanguage

View File

@ -0,0 +1 @@
net.sourceforge.pmd.lang.objectivec.ObjectiveCLanguageModule

View File

@ -0,0 +1,3 @@
# PMD Objective-C
Only CPD is supported. There are no PMD rules for Objective-C.

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/DECORATION/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd"
name="PMD Objective-C">
<body>
<menu ref="parent"/>
<menu ref="reports"/>
</body>
</project>

View File

@ -0,0 +1,27 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import java.util.Arrays;
import java.util.Collection;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.objectivec.ObjectiveCLanguageModule;
import org.junit.runners.Parameterized.Parameters;
public class LanguageVersionTest extends AbstractLanguageVersionTest {
public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) {
super(name, terseName, version, expected);
}
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ ObjectiveCLanguageModule.NAME, ObjectiveCLanguageModule.TERSE_NAME, "", LanguageRegistry.getLanguage(ObjectiveCLanguageModule.NAME).getDefaultVersion() }
});
}
}

View File

@ -0,0 +1,40 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.io.IOException;
import net.sourceforge.pmd.testframework.AbstractTokenizerTest;
import net.sourceforge.pmd.testframework.StreamUtil;
import org.junit.Before;
import org.junit.Test;
public class ObjectiveCTokenizerTest extends AbstractTokenizerTest {
private static final String FILENAME = "AFHTTPRequestOperation.m";
@Before
@Override
public void buildTokenizer() {
this.tokenizer = new ObjectiveCTokenizer();
this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), FILENAME));
}
@Override
public String getSampleCode() {
return StreamUtil.toString(ObjectiveCTokenizer.class.getResourceAsStream(FILENAME));
}
@Test
public void tokenizeTest() throws IOException {
this.expectedTokenCount = 884;
super.tokenizeTest();
}
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(ObjectiveCTokenizerTest.class);
}
}

View File

@ -0,0 +1,209 @@
// This sample file was copied from the AFNetworking GitHub project. (https://github.com/AFNetworking/AFNetworking)
// Original source file: https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFHTTPRequestOperation.m
//
// AFHTTPRequestOperation.m
//
// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "AFHTTPRequestOperation.h"
static dispatch_queue_t http_request_operation_processing_queue() {
static dispatch_queue_t af_http_request_operation_processing_queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_http_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.http-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_http_request_operation_processing_queue;
}
static dispatch_group_t http_request_operation_completion_group() {
static dispatch_group_t af_http_request_operation_completion_group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_http_request_operation_completion_group = dispatch_group_create();
});
return af_http_request_operation_completion_group;
}
#pragma mark -
@interface AFURLConnectionOperation ()
@property (readwrite, nonatomic, strong) NSURLRequest *request;
@property (readwrite, nonatomic, strong) NSURLResponse *response;
@end
@interface AFHTTPRequestOperation ()
@property (readwrite, nonatomic, strong) NSHTTPURLResponse *response;
@property (readwrite, nonatomic, strong) id responseObject;
@property (readwrite, nonatomic, strong) NSError *responseSerializationError;
@property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
@end
@implementation AFHTTPRequestOperation
@dynamic lock;
- (instancetype)initWithRequest:(NSURLRequest *)urlRequest {
self = [super initWithRequest:urlRequest];
if (!self) {
return nil;
}
self.responseSerializer = [AFHTTPResponseSerializer serializer];
return self;
}
- (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
NSParameterAssert(responseSerializer);
[self.lock lock];
_responseSerializer = responseSerializer;
self.responseObject = nil;
self.responseSerializationError = nil;
[self.lock unlock];
}
- (id)responseObject {
[self.lock lock];
if (!_responseObject && [self isFinished] && !self.error) {
NSError *error = nil;
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
if (error) {
self.responseSerializationError = error;
}
}
[self.lock unlock];
return _responseObject;
}
- (NSError *)error {
if (_responseSerializationError) {
return _responseSerializationError;
} else {
return [super error];
}
}
#pragma mark - AFHTTPRequestOperation
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
if (self.completionGroup) {
dispatch_group_enter(self.completionGroup);
}
dispatch_async(http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
success(self, responseObject);
});
}
}
}
if (self.completionGroup) {
dispatch_group_leave(self.completionGroup);
}
});
};
#pragma clang diagnostic pop
}
#pragma mark - AFURLRequestOperation
- (void)pause {
[super pause];
u_int64_t offset = 0;
if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue];
} else {
offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length];
}
NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy];
if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) {
[mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"];
}
[mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"];
self.request = mutableURLRequest;
}
#pragma mark - NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
}
self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
AFHTTPRequestOperation *operation = [super copyWithZone:zone];
operation.responseSerializer = [self.responseSerializer copyWithZone:zone];
operation.completionQueue = self.completionQueue;
operation.completionGroup = self.completionGroup;
return operation;
}
@end

View File

@ -864,6 +864,7 @@
<module>pmd-java</module>
<module>pmd-javascript</module>
<module>pmd-jsp</module>
<module>pmd-objectivec</module>
<module>pmd-php</module>
<module>pmd-plsql</module>
<module>pmd-ruby</module>