diogosmendonca / patternlanguage Goto Github PK
View Code? Open in Web Editor NEWA markup language to find and alert source code patterns.
License: GNU General Public License v3.0
A markup language to find and alert source code patterns.
License: GNU General Public License v3.0
No padrão abaixo são gerados dois alertas no lugar de um. O ideal seria marcar o método getInstance, não os modificadores e classe de retorno do método.
Padrão:
public class SomeSingleton {
//Alert: getInstance method should return instance attribute
public static SomeSingleton getInstance(){
//not_exists
return instance;
}
}
Código:
public class MySingleton
{
private static MySingleton instance;
private MySingleton(){
}
public static MySingleton getInstance(){
if(instance == null)
instance = new MySingleton();
return null;
}
}
Alerta gerado:
2020-10-26 10:34:17,571 INFO - File: .\src\main\java\com\github\diogosmendonca\MySingleton.java
2020-10-26 10:34:17,571 INFO - Alert Message: getInstance method should return instance attribute
2020-10-26 10:34:17,571 INFO - Start: L: 16 C: 5
2020-10-26 10:34:17,571 INFO - End: L: 16 C: 18
2020-10-26 10:34:17,571 INFO - Alert Message: getInstance method should return instance attribute
2020-10-26 10:34:17,571 INFO - Start: L: 16 C: 19
2020-10-26 10:34:17,572 INFO - End: L: 16 C: 30
Em algumas situações pode ser muito útil localizar padrões de nomes por prefixo e sufixo. Por exemplo, na implementação das verificações para um Facade precisamos localizar um grupo de Classes de por um pacote ou sufixo, identificando uma camada da aplicação que precisa ter seu acesso restrito via Façade. Veja o exemplo abaixo:
Padrão pretendido:
public class SomeFacade{
//Alert: a Business Object should be called in a Facade method.
public static String anyMethod(){
//not_exists
return sufixBusinessObject.anyMethod();
}
}
Código:
public class ControlFacade{
public static String diciplineSpecificService(){
return DiciplineBusinessObject.diciplineSpecificService();
}
public static String OtherSpecificService(){
return OtherBusinessObject.otherSpecificService();
}
}
Repare que os elementos que são chamados no facade tem todos um sufixo BusinessObject. Adicionalmente, eles estão incluídos todos no mesmo pacote, sendo possível localizá-los também se houver a possibilidade de identificar um pacote em um padrão.
O padrão de código abaixo não é encontrado quando está dentro de um switch.
Padrão:
public class SomeClass{
public static void main(String[] args){
//Alert: ControlFacade cannot be called from view package, call a command instead.
ControlFacade.someMethod();
}
}
Código:
package com.github.diogosmendonca.view;
import com.github.diogosmendonca.control.*;
public class Main{
private static String output = null;
public static void main(String[] args){
String result = null;
if(args != null && args.length > 0){
switch(args[0]){
case "studentSpecificCommand":
result = ControlFacade.studentSpecificService();
break;
case "diciplineSpecificCommand":
result = ControlFacade.diciplineSpecificService();
break;
default:
result = "Command not found";
break;
}
}else{
result = "Command not found";
}
System.out.println(result);
output = result;
}
public static String getOutput(){
return output;
}
}
Quando vamos utilizar o pré-processamento para gerar opções para um mesmo alerta acaba precisando repetir múltiplas vezes o comentário //Alert. Seria interessante ter uma forma de evitar isto. Veja o exemplo abaixo e a proposta de solução.
Exemplo do problema:
public class AnyClass{
//#BEGIN
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppA anyVariable;
//#OR
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppA anyVariable = null;
//#OR
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppA anyVariable = new AppA();
//#OR
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppB anyVariable;
//#OR
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppB anyVariable = null;
//#OR
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
AppB anyVariable = new AppB();
//#END
}
Proposta de solução. Esta proposta eu testei e ela não funciona.
public class AnyClass{
//Alert: Do not declare specific Apps (AppA or AppB) use the App instead.
//#BEGIN
AppA anyVariable;
//#OR
AppA anyVariable = null;
//#OR
AppA anyVariable = new AppA();
//#OR
AppB anyVariable;
//#OR
AppB anyVariable = null;
//#OR
AppB anyVariable = new AppB();
//#END
}
Hoje temos no pré-processamento o operador //#OR que nos dá a semântica de qualquer padrão que seja encontrado é retornado na busca. Contudo, existem casos onde é necessária a semântica AND, ou seja, quando todos os casos são encontrados é retornado um alerta (ou quando pelo menos um passa não é retornado um alerta). Veja o exemplo abaixo.
Na construção do padrão Command temos um atributo que mapeia os comandos. Este atributo deve existir, mas existem diversas formas de inicializá-lo. Somente quando nenhuma das formas está presente é que temos um problema devendo gerar um alerta. A implementação com o operador //#OR não contempla este caso, pois gera um alerta quando qualquer um deles falha. A semântica correta aqui seria existir um operador //#AND que quando todos os padrões geram alertas temos um problema, quando pelo menos um não gera alerta está tudo ok.
//Alert: Create in the invoker an static attribute that maps strings to command for store the commands.
public class SomeInvoker{
//#BEGIN
//not_exists
private static Map<String, Command> someVariableName;
//#AND
//not_exists
private static Map<String, Command> someVariableName = null;
//#AND
//not_exists
private static Map<String, Command> someVariableName = new AnyClass<>();
//#AND
//not_exists
private static Map<String, Command> someVariableName = new AnyClass<String, Command>();
//#END
}
Ao tentar verificar se uma determinada interface possui um método o padrão não é encontrado.
Padrão:
//Alert: Declare the method execute in command interface.
public interface SomeCommand{
//not_exists
public String execute();
}
Código:
package com.github.diogosmendonca.view.commands;
public interface Command {
}
Problema muito parecido com issue #15, só que com o not_exists. A chamada do método e atribuição existe, mas o alerta é gerado como se não existisse. Na verdade o ideal é que fosse somente a chamada do método anyVar.execute(), mas como a atribuição está no código tentei facilitar para o padrão e incluí a atribuição. Se eu tirar os ifs, e todo o outro código da main e deixar somente o padrão ele acha, mas esta não é a situação real de uso.
Padrão:
public class AnyClass {
//Alert: Use the commands map to get a command and execute it.
public static void main(String[] args){
//not_exists
anyVar = anyOtherVar.execute();
}
}
Padrão
package com.github.diogosmendonca.view;
import com.github.diogosmendonca.control.*;
import java.util.*;
import com.github.diogosmendonca.view.commands.*;
public class Main{
private static String output = null;
private static Map<String,Command> commands = new HashMap<>();
static{
commands.put("diciplineSpecificCommand", new DiciplineSpecificCommand());
commands.put("studentSpecificCommand", new StudentSpecificCommand());
}
public static void main(String[] args){
String result = null;
if(args != null && args.length > 0){
Command c = commands.get(args[0]);
if(c != null)
result = c.execute();
else
result = "Command not found";
}else{
result = "Command not found";
}
System.out.println(result);
output = result;
}
public static String getOutput(){
return output;
}
}
Alerta gerado:
2020-11-04 11:50:58,518 INFO - File: .\src\main\java\com\github\diogosmendonca\view\Main.java
2020-11-04 11:50:58,520 INFO - Alert Message: Use the commands map to get a command and execute it.
2020-11-04 11:50:58,530 INFO - Start: L: 18 C: 5
2020-11-04 11:50:58,553 INFO - End: L: 18 C: 43
No código abaixo o alerta não é gerado, acredito eu por conflito entre os anotations @AlertIfNotStatic e @AnyModifier. Contudo, ao retirar o @AnyModifier o alerta é gerado. Se for este mesmo o motivo do alerta não estar sendo gerado (como foi colocado @AnyModifier então não faz sentido @AlertIfNotStatic), seria bom informar o usuário que modificadores conflitantes estão sendo usados. Como se fosse um warning de compilação. Se for bug mesmo corrigir.
Padrão
public class SomeSingleton {
@AlertIfNotStatic("Instance attribute should be static")
@AnyModifier
SomeSingleton instance;
}
Código
public class MySingleton
{
private static MySingleton instance;
private MySingleton(){
}
public static MySingleton getInstance(){
if(instance == null)
instance = new MySingleton();
return null;
}
}
O seguinte padrão parece não estar funcionando corretamente. Todos os elementos do padrão existem, mas mesmo assim um alerta é retornada quando utilizado o not_exists.
Padrão:
public class SomeFacade{
//Alert: a Business Object should be called in a Facade method.
public static String diciplineSpecificService(){
//not_exists
return DiciplineBusinessObject.diciplineSpecificService();
}
}
Código:
package com.github.diogosmendonca.control;
public class ControlFacade{
public static String diciplineSpecificService(){
return DiciplineBusinessObject.diciplineSpecificService();
}
}
2020-10-26 14:27:35,150 INFO - File: .\src\main\java\com\github\diogosmendonca\control\ControlFacade.java
2020-10-26 14:27:35,151 INFO - Alert Message: a Business Object should be called in a Facade method.
2020-10-26 14:27:35,155 INFO - Start: L: 7 C: 5
2020-10-26 14:27:35,159 INFO - End: L: 7 C: 18
2020-10-26 14:27:35,159 INFO - Alert Message: a Business Object should be called in a Facade method.
2020-10-26 14:27:35,159 INFO - Start: L: 7 C: 19
2020-10-26 14:27:35,159 INFO - End: L: 7 C: 25
No padrão e código abaixo o alerta é gerado duas vezes. A primeira marca a classe, o que está correto. Já a segunda marca o método, o que está conceitualmente errado, visto que o alerta deveria ser gerado na classe e não faz sentido este tipo de alerta em um método.
Padrão:
//Alert: Create in facade studentSpecificService with the same name and signature from those it will expose. Make it call the business object.
public class SomeFacade{
//not_exists
public static String studentSpecificService(){
}
}
Código:
package com.github.diogosmendonca.control;
import com.github.diogosmendonca.control.*;
public class ControlFacade{
public static String diciplineSpecificService(){
return DiciplineBusinessObject.diciplineSpecificService();
}
}
Alerta Gerado:
2020-10-27 14:35:24,189 INFO - File: .\src\main\java\com\github\diogosmendonca\control\ControlFacade.java
2020-10-27 14:35:24,189 INFO - Alert Message: Create in facade studentSpecificService with the same name and signature from those it will expose. Make it call the business object.
2020-10-27 14:35:24,200 INFO - Start: L: 5 C: 1
2020-10-27 14:35:24,204 INFO - End: L: 5 C: 7
2020-10-27 14:35:24,204 INFO - Alert Message: Create in facade studentSpecificService with the same name and signature from those it will expose. Make it call the business object.
2020-10-27 14:35:24,204 INFO - Start: L: 7 C: 5
2020-10-27 14:35:24,205 INFO - End: L: 7 C: 18
Hoje não há forma de verificar se uma classe estende outra ou implementa uma determinada interface. Acredito que a melhor forma de implementar seja com anotation. @ShouldExtend("AlgumaClasse") @ShouldImplements("AlgumaInterface").
Exemplo:
@ShouldImplements("Command", "This class should implement the command interface")
public class SomeCommand{
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.